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

wwwserfer

Постоялец
Регистрация
22 Ноя 2007
Сообщения
103
Реакции
28
день добрый!

нашел тут решение для себя, запрос о котором писал Для просмотра ссылки Войди или Зарегистрируйся
само решение:

Для просмотра ссылки Войди или Зарегистрируйся

все бы хорошо, но зараза... слова и описания, указанные в 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);
    });
};

...и дело, как оказалось, не в кодировке файлов скрипта и файла словаря..

Помогите решить пожалуйста!
 
Твоя проблема таится в использовании регулярного выражения:
Код:
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";
 
Для просмотра ссылки Войди или Зарегистрируйся

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

P.S. Флаг "u" (кроме того, что я про него ничего не знаю:)) похоже не работает совершенно..
 
Код:
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 не видит границ русских слов
 
сам документ-то в какой кодировке? И glossary.txt?
 
pitkina
огромное спасибо, похоже что это реально работает:

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

Sammerset

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

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

P.S. Такую же проблему имею на Для просмотра ссылки Войди или Зарегистрируйся и также не знаю, как с ней справиться..

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 ));
 
Не могу отредактировать свое предыдущее сообщение...

Так никто не поможет с 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 =..........

Сломал мозг - как решить задачу? Помогите!



 
Назад
Сверху