Помогите c Regexp для кириллицы

Тема в разделе "JavaScript", создана пользователем wwwserfer, 1 июл 2012.

Модераторы: ZiX
  1. wwwserfer

    wwwserfer Постоялец

    Регистр.:
    22 ноя 2007
    Сообщения:
    86
    Симпатии:
    23
    день добрый!

    нашел тут решение для себя, запрос о котором писал здесь
    само решение:

    http://code.google.com/p/glossary-js

    все бы хорошо, но зараза... слова и описания, указанные в glossary.txt воспринимаются скриптом только тогда, когда они на латинице, кирилицу игнорирует..
    так как мои позниния в java ниже среднего, прошу помощи!
    сам искал решение но все так отдаленно, и мало понятно для меня...
    Понял лишь, что все дело в файле jquery.highlight.js, который и производит поиск слов и их определений в glossary.txt (возможно с jQuery.fn.highlight = function (words, options))

    его содержимое:
    Код:
    jQuery.extend({
        highlight: function (node, re, nodeName, className) {
            if (node.nodeType === 3) {
                var match = node.data.match(re);
                if (match) {
                    var highlight = document.createElement(nodeName || 'span');
                    highlight.className = className || 'highlight';
                    var wordNode = node.splitText(match.index);
                    wordNode.splitText(match[0].length);
                    var wordClone = wordNode.cloneNode(true);
                    highlight.appendChild(wordClone);
                    wordNode.parentNode.replaceChild(highlight, wordNode);
                    return 1; //skip added node in parent
                }
            } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                    !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                    !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
                for (var i = 0; i < node.childNodes.length; i++) {
                    i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
                }
            }
            return 0;
        }
    });
     
    jQuery.fn.unhighlight = function (options) {
        var settings = { className: 'highlight', element: 'span' };
        jQuery.extend(settings, options);
     
        return this.find(settings.element + "." + settings.className).each(function () {
            var parent = this.parentNode;
            parent.replaceChild(this.firstChild, this);
            parent.normalize();
        }).end();
    };
     
    jQuery.fn.highlight = function (words, options) {
        var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
        jQuery.extend(settings, options);
       
        if (words.constructor === String) {
            words = [words];
        }
        words = jQuery.grep(words, function(word, i){
          return word != '';
        });
        if (words.length == 0) { return this; };
     
        var flag = settings.caseSensitive ? "" : "i";
        var pattern = "(" + words.join("|") + ")";
        if (settings.wordsOnly) {
            pattern = "\\b" + pattern + "\\b";
        }
        var re = new RegExp(pattern, flag);
       
        return this.each(function () {
            jQuery.highlight(this, re, settings.element, settings.className);
        });
    };
    ...и дело, как оказалось, не в кодировке файлов скрипта и файла словаря..

    Помогите решить пожалуйста!
     
  2. recasher2k12

    recasher2k12

    Регистр.:
    19 фев 2012
    Сообщения:
    156
    Симпатии:
    78
    Твоя проблема таится в использовании регулярного выражения:
    Код:
    var flag = settings.caseSensitive ? "" : "i";
    var pattern = "(" + words.join("|") + ")";
    if (settings.wordsOnly) {
    pattern = "\\b" + pattern + "\\b";
    }
    var re = new RegExp(pattern, flag);
    Почему-то не всегда понимает символы utf.
    Попробуй заменить
    Код:
    var flag = settings.caseSensitive ? "" : "i";
    на
    Код:
    var flag = "u" + settings.caseSensitive ? "" : "i";
     
    wwwserfer нравится это.
  3. wwwserfer

    wwwserfer Постоялец

    Регистр.:
    22 ноя 2007
    Сообщения:
    86
    Симпатии:
    23
    recasher2k12

    Спасибо, попробовал, но, увы, результат нулевой... также не цепляет русские слова из словаря

    P.S. Флаг "u" (кроме того, что я про него ничего не знаю:)) похоже не работает совершенно..
     
  4. pitkina

    pitkina

    Регистр.:
    1 апр 2007
    Сообщения:
    253
    Симпатии:
    176
    Код:
    var wordNode = node.splitText(match.index);
    var wordNode = node.splitText(match.index+!!(match[1].length));
    wordNode.splitText(match[2].length);
    ...
    if (settings.wordsOnly) {
    pattern = "(\\W|^)" + pattern + "(\\W|$)";
    }
    \b не видит границ русских слов
     
    wwwserfer нравится это.
  5. Sammerset

    Sammerset Постоялец

    Регистр.:
    14 сен 2008
    Сообщения:
    136
    Симпатии:
    10
    сам документ-то в какой кодировке? И glossary.txt?
     
  6. wwwserfer

    wwwserfer Постоялец

    Регистр.:
    22 ноя 2007
    Сообщения:
    86
    Симпатии:
    23
    pitkina
    огромное спасибо, похоже что это реально работает:

    Код:
    pattern = "(\\W|^)" + pattern + "(\\W|$)";
    Sammerset

    сам документ в ANSI, glossary.txt в UTF-8 конечно же..

    Вообщем буду тестировать дальше.. Может еще какие баги появятся..
     
  7. wwwserfer

    wwwserfer Постоялец

    Регистр.:
    22 ноя 2007
    Сообщения:
    86
    Симпатии:
    23
    И еще, чтобы не создавать лишние темы, помогите пожалуйста, как правильно прописать, чтобы совпадение было однократным, т.е. к примеру, у меня в тексте присутствует слово "медь" несколько раз, соответственно, если я заранее прописал это слово в glossary.txt, то все его совпадения подчеркиваются, а нужно чтобы подчеркивалось только первое совпадение, а остальные игнорировались. Это возможно?

    P.S. Такую же проблему имею на jquery-thesaurus и также не знаю, как с ней справиться..

    jquery.thesaurus.js

    Код:
    /*
    * Thesaurus
    *
    * @package thesaurus
    * @author sheiko
    * @version jquery.thesaurus.js, v 4.0
    * @license GNU
    * @copyright (c) Dmitry Sheiko http://dsheiko.com
    */
     
    (function( $ ) {
        var VERSION = "4.0b",
            TPL_TAG_OPEN = '~~',
            TPL_TAG_CLOSE = '~~',
            ESCAPERS = '[\\s!;,%\"\'\\(\\)\\{\\}]',
            SERVER_LOC = 'server.php',
            UNAPPROPRIATE_TAGS = ['SCRIPT', 'BASE', 'LINK', 'META', 'STYLE', 'TITLE', 'APPLET', 'OBJECT'],
            CSS_TPL =
            'div.thesaurus { font-size: 12px; font-family: Arial; position: absolute; width: 300px; z-index: auto;  box-shadow: 0 0 5px #000000; -moz-box-shadow: 0 0 5px #000000; -webkit-box-shadow: 0 0 5px #000000; -o-box-shadow: 0 0 5px #000000; -ie-box-shadow: 0 0 5px #000000; border-radius: 5px;  -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; -ie-border-radius: 5px; }' +
            'div.thesaurus > div.thesaurus-canvas { position: relative; }' +
            'div.thesaurus .thesaurus-header {  padding: 6px;  background-color: #3C5F87;  border-radius: 5px 5px 0 0; -moz-border-radius: 5px 5px 0 0; -webkit-border-radius: 5px 5px 0 0;  -o-border-radius: 5px 5px 0 0;  -ie-border-radius: 5px 5px 0 0;  }' +
            'div.thesaurus .thesaurus-header a { color: white; font-weight: bold; }' +
            'div.thesaurus .thesaurus-header a.reference { position: absolute; right: 6px; z-index: auto; display: block; }' +
            'div.thesaurus .thesaurus-body { padding: 5px;  border: 1px solid #3C5F87; background-color: #fff; border-radius: 0 0 5px 5px; -moz-border-radius: 0 0 5px 5px; -webkit-border-radius: 0 0 5px 5px; -o-border-radius: 0 0 5px 5px; -ie-border-radius: 0 0 5px 5px;  }' +
            'dfn.thesaurus { text-decoration: none; font-style: inherit; border-bottom: 1px dashed black; cursor: pointer; }' +
            "div.thesaurus > div.thesaurus-canvas:after { content: ''; position: absolute; width: 0; height: 0; border: 5px solid; }" +
            'div.thesaurus > div.thesaurus-canvas.upwards:after { border-color: #3C5F87 transparent transparent transparent; top: 100%; }' +
            'div.thesaurus > div.thesaurus-canvas.rightwards:after { margin-left: 10px; left: 0; }' +
            'div.thesaurus > div.thesaurus-canvas.leftwards:after { margin-right: 10px; right: 0; }' +
            'div.thesaurus > div.thesaurus-canvas.downwards:after { border-color: transparent transparent #3C5F87 transparent;  bottom: 100%; }' +
            '.thesaurus-fade-start { opacity: 0; }' +
            '.thesaurus-fade-end { -webkit-transition: opacity 1s ease-in-out;  -moz-transition: opacity 1s ease-in-out; -o-transition: opacity 1s ease-in-out; transition: opacity 1s ease-in-out; opacity: 1 !important; }',
       
            TOOLTIP_TPL = '<div class="thesaurus"><div class="thesaurus-canvas"><div class="thesaurus-header"><a class="reference" target="_blank" href="http://dsheiko.com/freeware/">Thesaurus v.' + VERSION +'</a><a class="term"></a></div><div class="thesaurus-body">Loading...</div></div></div>',
            TOOLTIP_HIDE_TIMEOUT = 100,
            PUSH_TIMEOUT = 5000,
            thesaurusInstance = null,
            Repository = { // Global repository
                termsDef: {},  // Cache of term definitions
                targetId: 0
            },
            /**
            * Thesaurus Data Access Object
            */
            DAO = {
                /**
                * Encode strings with spaces correctly
                * @param string text
                */
                _urlEncode: function(text) {
                    return encodeURIComponent(text.replace(/ /g, "+"));
                },
                /**
                * Makes a JSONP request to server
                * @param string action
                * @param string term
                * @param boolean caseSensitive
                * @param function callback
                */
                request: function(action, data, callback) {
                   
                    $.getScript(SERVER_LOC + "?action=" + action
                        + (typeof data.term !== "undefined"
                            ? "&term=" + DAO._urlEncode(data.term) : "")
                        + (typeof data.stats !== "undefined"
                            ? "&stats=" + DAO._urlEncode(data.stats) : "")
                        + (typeof data.caseSensitive !== "undefined"
                            ? "&caseSensitive=" + (data.caseSensitive * 1) : ""), callback);
                }
            }
            /**
            * Statistics collector
            */
            Stats = function() {
                var _termViews = {},
                    _pushCb = function() {
                        if (Object.keys(_termViews).length) {
                            DAO.request("onview", {'stats': JSON.stringify(_termViews)}, function() {
                                _termViews = {};
                            });
                        }
                    };
                return {
                    establishServerPushConnection: function() {                   
                        window.setInterval(_pushCb, PUSH_TIMEOUT);
                        $(window).unload(_pushCb);
                    },
                    /**
                    * Collect term view stats, which can be pushed to the server with session close
                    * @param string term
                    */
                    incrementTermViews: function(term) {
                        term = (term + "").toLowerCase();
                        _termViews[term] = typeof _termViews[term] === "undefined"
                            ? 1 :  _termViews[term] + 1;
                    },
                    /**
                    * Collect term click stats
                    * @param string term
                    */
                    incrementTermClicks: function(term) {
                        DAO.request("onclick", {'term': term});
                    }
                }
            },
            /**
            * Tooltip manager
            * @param Tooltip parent - the link to the parent tooltip if one exists
            */
            Tooltip = function(parent) {
                var _settings = thesaurusInstance.getSettings(),
                    _statsInstance = thesaurusInstance.getStatsInstance(),
                    _parent = parent,
                    _boundingBox = null,
                    _hideTimer = null,
                    _id = 0,
                    /**
                    * Adjusts position (top/left) of the tooltip overlay relatively to term element
                    */
                    _adjustPositionByTarget = function(targetEl) {
                        var top = targetEl.offset().top - 5 - _boundingBox.height(),
                            left = targetEl.offset().left + targetEl.width() / 2,
                            canvas = _boundingBox.find(' > .thesaurus-canvas');
                       
                        canvas.removeClass('upwards').removeClass('downwards')
                            .removeClass('leftwards').removeClass('rightwards');
                       
                        if (top  < $(window).scrollTop()) {
                            top = targetEl.offset().top + targetEl.height() + 5;
                            canvas.addClass('downwards');
                        } else {
                            canvas.addClass('upwards');
                        }
                       
                        if (left > $(window).width() - _boundingBox.width()) {
                            left = targetEl.offset().left - _boundingBox.width() + targetEl.width() / 2;
                            canvas.addClass('leftwards');
                        } else {
                            canvas.addClass('rightwards');
                        }
                        _boundingBox
                                .css("top", Math.floor(top))
                                .css("left", Math.floor(left))
                    },
                    /**
                    * Fetches definitiion of the provided term by XMLHttpRequest or from cache
                    */
                    _fetchDefinition = function(term, callback){
                        if (typeof Repository.termsDef[term] !== "undefined") {
                            callback(Repository.termsDef[term]);
                            return;
                        }
                        DAO.request("termDef", {'term' : term,
                            'caseSensitive' : _settings.caseSensitive}, function() {
                            Repository.termsDef[term] = $.callbackData.payload;
                            callback(Repository.termsDef[term]);
                        });
                    },
                    /**
                    * Assigns CSS3 transition effect, if any specified
                    * @param string state
                    */
                    _setTransitionState = function(state) {
                        if (_settings.effect) {
                            _boundingBox.addClass('thesaurus-' + _settings.effect + '-' + state);
                        } 
                    };
                return {
                    /**
                    * Subscribes handlers on hover events on the terms elements in DOM
                    */
                    syncUI: function(nodes) {
                        nodes.find('dfn.thesaurus').unbind().bind("mouseenter", this, function(e){
                            e.data.show($(this));
                        }).bind('mouseleave', this, function(e){
                            e.data.hide();
                        });
                    },
                    /**
                    * Subscribes handlers on events within tooltip overlay
                    * @param string term
                    */
                    syncOverlayUI : function(term) {
                        _boundingBox.unbind().bind("mouseenter", this, function(e){
                            e.data.cancelHiding();
                        }).bind('mouseleave', this, function(e){
                            e.data.hide();
                        }).bind('click', this, function(){
                          _statsInstance.incrementTermClicks(term);
                        })
                    },
                    /**
                    * Renders tooltip overlay
                    * @param jQuery Node
                    **/
                    show: function(targetEl) {
                        var term = targetEl.text(), id = targetEl.data('id'), scope = this;
                       
                        _statsInstance.incrementTermViews(term);
                       
                        // Happens when mouse cursor moves from overlay to the target link
                        if (id && _id === id && _boundingBox.hasClass('thesaurus-visible')) {
                            this.cancelHiding();
                            return;
                        }
                        if (typeof id === "undefined") {
                            targetEl.data('id', _id = ++Repository.targetId);
                        }
                        $(_boundingBox).remove();
                        // Renders tooltip with Loading...
                        _boundingBox = $(TOOLTIP_TPL).appendTo('body');
                        _boundingBox.find('a.term').text(term);
                        // IE 8 supports :after CSS pseudo-property, buut doesn't transporent border-color
                        if ($.browser.msie && Math.floor($.browser.version) < 10) {
                            _boundingBox.find(' > .thesaurus-canvas').removeClass('thesaurus-canvas');
                        }
                        _boundingBox
                            .addClass('thesaurus-visible');
                        _setTransitionState('start');
                       
                       
                        this.syncOverlayUI(term);
                     
                        _adjustPositionByTarget(targetEl);
                        // Fetches and appends definition text into the tooltip
                        _fetchDefinition(term, function(def){
                            thesaurusInstance.run(
                                _boundingBox.find('div.thesaurus-body').html(def), scope);
                            _adjustPositionByTarget(targetEl);
                        });
                        _setTransitionState('end');
                    },
                    /**
                    * Cancel destroying
                    */
                    cancelHiding: function() {
                        window.clearTimeout(_hideTimer);
                        if (typeof _parent !== 'undefined') {
                            _parent.cancelHiding();
                        }
                    },
                    /**
                    * Destroys tooltip overlay defferedly
                    */
                    hide: function() {
                        if (typeof _parent !== 'undefined') {
                            _parent.hide();
                        }
                        window.clearTimeout(_hideTimer);
                        _hideTimer = window.setTimeout(function(){                       
                            _boundingBox
                                .removeClass('thesaurus-visible').remove();
                        }, TOOLTIP_HIDE_TIMEOUT);
                    }
                }
            },
           
            /**
            * Plugin's manager
            */
            Thesaurus = function(settings) {
                var _settings = $.extend({
                    caseSensitive: false,
                    effect: null,
                    pushStats: false               
                }, settings),
                _terms = {},
                _statsInstance = new Stats(),
                /**
                * Since I know no way to insert an ElementNode into a TextNode, here the found term
                * is marked with special text tags, to be found and replaced aftewards within DOM
                *
                * @param string line
                * @param string term
                */
                _markTermInTextNodeText = function(line, term) {
                    var modifier = _settings.caseSensitive ? "g" : "gi";
                    // Only term in nodeValue
                    if(term == line) {
                        return TPL_TAG_OPEN + line + TPL_TAG_CLOSE;
                    }
                    //term" ....
                    var re = new RegExp("^("+term+")(" + ESCAPERS + ")", modifier);
                    line = line.replace(re, TPL_TAG_OPEN + "$1" + TPL_TAG_CLOSE + "$2");
                    //... "term
                    re = new RegExp("(" + ESCAPERS + ")("+term+")$", modifier);
                    line = line.replace(re, "$1" + TPL_TAG_OPEN + "$2" + TPL_TAG_CLOSE);
                    // .. "term" ..
                    re = new RegExp("(" + ESCAPERS + ")("+term+")(" + ESCAPERS + ")", modifier);
                    line = line.replace(re, "$1" + TPL_TAG_OPEN +"$2" + TPL_TAG_CLOSE + "$3");
                    return line;
                },
                /**
                * Mark terms in TextNodes of the given parent nodes
                * @param jQuery nodes
                */
                _markTermsInDOM = function(nodes) {
                  nodes.contents().filter(function() {
                        // If it is an element, look for text nodes inside recursively
                        if (this.nodeType === 1) {
                            _markTermsInDOM($(this));
                        }
                        // Only not empty text nodes
                        return this.nodeType === 3 && $.trim($(this).text()).length
                            && $.inArray(this.tagName, UNAPPROPRIATE_TAGS) === -1;
                  })
                  .each(function(){
                      var node = this;
                      $.each(_terms, function(id, term){
                          node.nodeValue = _markTermInTextNodeText(node.nodeValue, term);
                      })
                  });
                },
                /**
                * Turn found terms into elements responsible to hover event
                * @param jQuery nodes
                */
                _wrapTermsInDOM = function(nodes) {
                    nodes.find('script').detach();
                    nodes.html(function(inx, html){
                        var re = new RegExp(TPL_TAG_OPEN + "(.*?)" + TPL_TAG_OPEN, 'g');
                        return html.replace(re, '<dfn class=\"thesaurus\">$1</dfn>');
                  });
                };
     
            return {
                init: function(callback) {
                  if (_settings.pushStats) {
                      _statsInstance.establishServerPushConnection();
                  }
                  this.renderUI();
                  this.loadTerms(callback);
                  return this;
                },
                run: function(nodes, parent) {
                    _markTermsInDOM(nodes);
                    _wrapTermsInDOM(nodes);
                    var tooltipInstance = new Tooltip(parent)
                    tooltipInstance.syncUI(nodes);
                },
                /**
                * Loads terms map {id : term} from the data source
                * @param function callback
                */
                loadTerms: function(callback) {
                    var scope = this;
                    DAO.request("termList", {}, function(){
                        _terms = $.callbackData.payload;
                        callback.call(scope);
                    });
                },
                /**
                * Adding Thesaurus stylesheet into DOM
                */
                renderUI : function() {
                    // Append CSS
                    $('body').append('<style type="text/css">' + CSS_TPL + '</style>');
                },
                /**
                * Public accessor
                */
                getSettings: function() {
                    return _settings;
                },
                /**
                * Public accessor
                */
                getStatsInstance: function() {
                    return _statsInstance;
                }
     
        }};
        /**
        * @param object settings
        * @param Thesaurus parent - required only when Thesaurus instatiated to parse tooltip's content
        */
        $.fn.Thesaurus = function(settings) {
            var nodes = $(this);
            if (thesaurusInstance === null) {
                thesaurusInstance = new Thesaurus(settings);
                thesaurusInstance.init(function(){
                    thesaurusInstance.run(nodes);
                });
            } else {
                thesaurusInstance.run(nodes);
            }
        };
       
     
    }( jQuery ));
     
  8. wwwserfer

    wwwserfer Постоялец

    Регистр.:
    22 ноя 2007
    Сообщения:
    86
    Симпатии:
    23
    Не могу отредактировать свое предыдущее сообщение...

    Так никто не поможет с jquery.thesaurus.js?

    Путем поиска информации в инете, я понял, что для первого найденного однократного вхождения мне стоило поменять с

    Код:
    var re = new RegExp(TPL_TAG_OPEN + "(.*?)" + TPL_TAG_OPEN, 'g');
    на

    Код:
    var re = new RegExp(TPL_TAG_OPEN + "(.*?)" + TPL_TAG_OPEN, 'i');
    ну или вообще ничего не указывать:

    Код:
    var re = new RegExp(TPL_TAG_OPEN + "(.*?)" + TPL_TAG_OPEN);
    но вот проблема - первое вхождение нормальное, а остальные похожие слова все с тильдами:

    т.е. медь ~~медь~~ ~~Медь~~ ~~МЕДЬ~~

    Полагаю, что из-за такого "нахождения" терминов:

    Код:
    /**
                * Since I know no way to insert an ElementNode into a TextNode, here the found term
                * is marked with special text tags, to be found and replaced aftewards within DOM
                *
                * @param string line
                * @param string term
                */
                _markTermInTextNodeText = function(line, term) {
                    var modifier = _settings.caseSensitive ? "g" : "gi";
                    // Only term in nodeValue
                    if(term == line) {
                        return TPL_TAG_OPEN + line + TPL_TAG_CLOSE;
                    }
                    //term" ....
                    var re = new RegExp("^("+term+")(" + ESCAPERS + ")", modifier);
                    line = line.replace(re, TPL_TAG_OPEN + "$1" + TPL_TAG_CLOSE + "$2");
                    //... "term
                    re = new RegExp("(" + ESCAPERS + ")("+term+")$", modifier);
                    line = line.replace(re, "$1" + TPL_TAG_OPEN + "$2" + TPL_TAG_CLOSE);
                    // .. "term" ..
                    re = new RegExp("(" + ESCAPERS + ")("+term+")(" + ESCAPERS + ")", modifier);
                    line = line.replace(re, "$1" + TPL_TAG_OPEN +"$2" + TPL_TAG_CLOSE + "$3");
                    return line;
                },
    и из-за этого:

    Код:
    (function( $ ) {
        var VERSION = "4.0b",
            TPL_TAG_OPEN = '~~',
            TPL_TAG_CLOSE = '~~',
            ESCAPERS = '[\\s!;,%\"\'\\(\\)\\{\\}]',
            SERVER_LOC = 'server.php',
            UNAPPROPRIATE_TAGS = ['SCRIPT', 'BASE', 'LINK', 'META', 'STYLE', 'TITLE', 'APPLET', 'OBJECT'],
            CSS_TPL =..........
    Сломал мозг - как решить задачу? Помогите!