文本匹配不适用于阿拉伯语问题可能是由于阿拉伯语的正则表达式

时间:2013-05-21 07:17:58

标签: jquery regex highlight

我一直在努力为我的多语种网站添加功能,我必须突出显示匹配的标记关键字。

此功能适用于英文版,但不适用于阿拉伯语版本。

我已在jsFiddle

上设置了示例

示例代码

    function HighlightKeywords(keywords)
    {        
        var el = $("#article-detail-desc");
        var language = "ar-AE";
        var pid = 32;
        var issueID = 18; 
        $(keywords).each(function()
        {
           // var pattern = new RegExp("("+this+")", ["gi"]); //breaks html
            var pattern = new RegExp("(\\b"+this+"\\b)(?![^<]*?>)", ["gi"]); //looks for match outside html tags
            var rs = "<a class='ad-keyword-selected' href='http://www.alshindagah.com/ar/search.aspx?Language="+language+"&PageId="+pid+"&issue="+issueID+"&search=$1' title='Seach website for:  $1'><span style='color:#990044; tex-decoration:none;'>$1</span></a>";
            el.html(el.html().replace(pattern, rs));
        });
    }   

HighlightKeywords(["you","الهدف","طهران","سيما","حاليا","Hello","34","english"]);

//Popup Tooltip for article keywords
     $(function() {
        $("#article-detail-desc").tooltip({
        position: {
            my: "center bottom-20",
            at: "center top",
            using: function( position, feedback ) {
            $( this ).css( position );
            $( "<div>" )
            .addClass( "arrow" )
            .addClass( feedback.vertical )
            .addClass( feedback.horizontal )
            .appendTo( this );
        }
        }
        });
    });

我将关键字存储在数组&amp;然后将它们与特定div中的文本匹配。

我不确定是由于Unicode还是什么问题。感谢这方面的帮助。

1 个答案:

答案 0 :(得分:7)

这个答案有三个部分

  1. 为什么不能正常工作

  2. 一个如何用英语接近它的例子(意在被一个有阿拉伯语线索的人改编成阿拉伯语)

  3. 一个人(我)对阿拉伯语版本进行了抨击,他对阿拉伯语一无所知: - )

  4. 为什么它不起作用

    至少部分问题在于您依赖的\b assertion(与其对应的\B\w\W一样)是英语 - 中心。你不能在其他语言中依赖它(甚至,真的,用英语 - 见下文)。

    以下是the spec\b的定义:

      

    生产断言:: \ b通过返回一个带有AssertionTester参数State的内部x闭包进行求值,并执行以下操作:

         
        
    • ex endIndex
    •   
    • 致电IsWordChar(e–1)并让a成为Boolean结果。
    •   
    • 致电IsWordChar(e)并让b成为Boolean结果。
    •   
    • 如果atruebfalse,请返回true
    •   
    • 如果afalsebtrue,请返回true
    •   
    • 返回false
    •   

    ...其中IsWordChar被进一步定义为基本上意味着这63个字符中的一个:

    a  b  c  d  e  f  g  h  i  j  k  l  m  n  o  p  q  r  s  t  u  v  w  x  y  z
    A  B  C  D  E  F  G  H  I  J  K  L  M  N  O  P  Q  R  S  T  U  V  W  X  Y  Z
    0  1  2  3  4  5  6  7  8  9  _    

    ,例如,大写或小写的26个英文字母az09,以及_。 (这意味着您甚至不能依赖英语中的\b\B\w\W,因为English有“Voilà”之类的借词,但这是另一个故事。)

    使用英语的第一个例子

    您必须使用不同的机制来检测阿拉伯语中的单词边界。如果你能想出一个包含构成单词的所有阿拉伯语“代码点”(如Unicode所说)的字符类,你可以使用类似这样的代码:

    var keywords = {
        "laboris": true,
        "laborum": true,
        "pariatur": true
        // ...and so on...
    };
    var text = /*... get the text to work on... */;
    text = text.replace(
        /([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]+)([^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]+)?/g,
        replacer);
    
    function replacer(m, c0, c1) {
        if (keywords[c0]) {
            c0 = '<a href="#">' + c0 + '</a>';
        }
        return c0 + c1;
    }
    

    注意事项:

    • 我使用班级[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]来表示“一个字符”。显然你必须为阿拉伯语改变它(显着)。
    • 我使用班级[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]来表示“不是一个单词字符”。这与前面的类一样,在开始时使用否定(^)。
    • 正则表达式使用捕获组((...))查找任何一系列“单词字符”,后跟可选系列非单词字符。
    • String#replace使用匹配的全文调用replacer函数,后跟每个捕获组作为参数。
    • replacer函数在keywords地图中查找第一个捕获组(单词)以查看它是否为关键字。如果是这样,它将它包裹在一个锚中。
    • replacer函数返回可能包含的单词加上其后的非单词文本。
    • String#replace使用replacer的返回值替换匹配的文本。

    以下是完成此操作的完整示例:Live Copy | Live Source

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset=utf-8 />
    <title>Replacing Keywords</title>
    </head>
    <body>
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    
      <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
      <script>
        (function() {
          // Our keywords. There are lots of ways you can produce
          // this map, here I've just done it literally
          var keywords = {
            "laboris": true,
            "laborum": true,
            "pariatur": true
          };
    
          // Loop through all our paragraphs (okay, so we only have one)
          $("p").each(function() {
            var $this, text;
    
            // We'll use jQuery on `this` more than once,
            // so grab the wrapper
            $this = $(this);
    
            // Get the text of the paragraph
            // Note that this strips off HTML tags, a
            // real-world solution might need to loop
            // through the text nodes rather than act
            // on the full text all at once
            text = $this.text();
    
            // Do the replacements
            // These character classes match JavaScript's
            // definition of a "word" character and so are
            // English-centric, obviously you'd change that
            text = text.replace(
              /([abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]+)([^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]+)?/g,
              replacer);
    
            // Update the paragraph
            $this.html(text);
          });
    
          // Our replacer. We define it separately rather than
          // inline because we use it more than once      
          function replacer(m, c0, c1) {
            // Is the word in our keywords map?
            if (keywords[c0]) {
              // Yes, wrap it
              c0 = '<a href="#">' + c0 + '</a>';
            }
            return c0 + c1;
          }
        })();
      </script>
    </body>
    </html>
    

    用阿拉伯语

    进行攻击 我抓住了阿拉伯语版本。根据维基百科上的Arabic script in Unicode page,使用了几个代码范围,但是您的示例中的所有文本都属于U + 0600到U + 06FF的主要范围。

    以下是我提出的问题:Fiddle(我更喜欢JSBin,我上面使用过的,但是我无法让文字以正确的方式出现。)

    (function() {
        // Our keywords. There are lots of ways you can produce
        // this map, here I've just done it literally
        var keywords = {
            "الهدف": true,
            "طهران": true,
            "سيما": true,
            "حاليا": true
        };
    
        // Loop through all our paragraphs (okay, so we only have two)
        $("p").each(function() {
            var $this, text;
    
            // We'll use jQuery on `this` more than once,
            // so grab the wrapper
            $this = $(this);
    
            // Get the text of the paragraph
            // Note that this strips off HTML tags, a
            // real-world solution might need to loop
            // through the text nodes rather than act
            // on the full text all at once
            text = $this.text();
    
            // Do the replacements
            // These character classes just use the primary
            // Arabic range of U+0600 to U+06FF, you may
            // need to add others.
            text = text.replace(
                /([\u0600-\u06ff]+)([^\u0600-\u06ff]+)?/g,
                replacer);
    
            // Update the paragraph
            $this.html(text);
        });
    
        // Our replacer. We define it separately rather than
        // inline because we use it more than once      
        function replacer(m, c0, c1) {
            // Is the word in our keywords map?
            if (keywords[c0]) {
                // Yes, wrap it
                c0 = '<a href="#">' + c0 + '</a>';
            }
            return c0 + c1;
        }
    })();
    

    我在上面的英语功能中做的就是:

    • 使用[\u0600-\u06ff]为“单词字符”,[^\u0600-\u06ff]为“不是单词字符”。您可能需要添加一些其他范围listed here(例如相应的数字样式),但同样,示例中的所有文本都属于这些范围。
    • 从您的示例中将关键字更改为您的三个(其中只有两个似乎在文本中)。

    对于非常非阿拉伯语阅读的眼睛,它似乎有效。