JS 正则表达式以匹配 HTML 标记中不是 <a> 的字符串

JS Regex to match a string within HTML tags that aren't <a>

本文关键字:字符串 正则表达式 HTML JS      更新时间:2023-09-26

我正在使用jQuery来突出显示文章中的缩写,并且正在为我的正则表达式而苦苦挣扎。

我正在尝试匹配特定文本,该文本是HTML标签中的单词(而不是在<img src="abbr" />等属性中),不是另一个单词的一部分,也不是<a>标签中。

然后,我将用一个<abbr>标签和一个指向词汇表的链接来包装它。

我已经有了一点方法,我当前的正则表达式如下所示:

('>[^'>]*'W)abbr('W[^'>=]*'<)

其中"abbr"是我试图匹配的缩写。这种工作有效,但如果缩写是一行的第一个单词,或者如果它在<a>标签内,则不起作用。

我想匹配的这些"缩写"实例:

<p>Lorem abbr ipsum</p>
<p>abbr lorem abbr</p>
<ul>
  <li>abbr abbr</li>
  <li>abbr</li>
</ul>

而我不想匹配以下任何一项:

<p><a href="abbr.html">abbr</a></p>
<img src="abbr.jpg" />
<p>Lormabbripsum</p>

为此,我在我的文章中选择了所有 HTML,目的是进行字符串替换。我的JS看起来像这样

$.getJSON("glossaryjson", function (data) {
    var str = $('.article-body').html();
    var i;
    for (i = 0; i < data.length; i++) {
        var regex = new RegExp("('>[^'p>]*''W)" + data[i].name + "(''W[^'>=]*'<)");
        str = str.replace(regex, '$1<abbr title="' + data[i].desc + '"><a href="/glossary?f=' + data[i].letter + '">' + data[i].name + '</a></abbr>$2');
            }
    $('.article-body').html(str);
});

我们可以使用单词边界 '''b' 来阻止它在单词中间找到缩写。然而,它并不完美。假设您正在寻找 I.A.它会在CIA中找到匹配项,因为句点是单词边界的一部分。

此外,我们可以使用积极的前瞻(LA)和消极的展望(NLA)来展望并根据内容做出决定。

我不认为正则表达式是理想的,因为单词边界问题,因为当在 html 文档中投下如此广泛的网时,事情可能会变得毛茸茸的(如果你不理想的 html)

'babbr'b(?=(?![^>]*<'/a>)[^>]*)
'b             # Token: 'b
                 # word boundary
abbr           # Literal abbr
'b             # Token: 'b
                 # word boundary
(?=            # Opens LA
 (?!           # Opens NLA
  [^>]*        # Negated Character class (excludes the characters within)
                 # None of: >
                 # * repeats zero or more times
  <'/a>        # Literal </a>
 )             # Closes NLA
 [^>]*         # Negated Character class (excludes the characters within)
                 # None of: >
                 # * repeats zero or more times
                 # Literal <
)              # Closes LA

如果你同意使用 jQuery,你可以找到与你想要的匹配的元素(不是<a>元素,也不是父元素),然后只使用那些带有正则表达式匹配的文本的元素。例如。。。

$(':not(a, :has(*))').filter(function(i,e){return !!e.innerHTML.match(/'babbr'b/)})

否则,你只需要做类似的事情......

function filterAbbr() {
    var all = document.getElementsByTagName('*');
    var filter = [];
    for(var i=0; i<all.length; i++) {
        if(!all[i].children.length && all[i].tagName != 'A') {
            filter.push(all[i]);
        }
    }
    all = [];
    for(var i=0; i<filter.length; i++) {
        if(filter[i].innerHTML.match(/'babbr'b/)) {
            all.push(filter[i]);
        }
    }
    return all;
}