正则表达式:对不支持的负向外观使用负向外观,并在拆分时捕获字符的向后外观

时间:2019-04-13 05:41:13

标签: javascript regex

我再次在正则表达式方面苦苦挣扎。我一直在尝试使用转义字符来将自定义标签(例如<1>转换为<57>,将</1>转换为</57>。在here的帮助下,以下表达式在尝试转义方法之前会产生所需的结果。

('This is a <21>test</21> again.').split(/(<\/?(?:[1-9]|[1-4][0-9]|5[0-7])>)/);

生成'This is a ', '<21>', 'test', '</21>', ' again.'

This问题中的一个建议是使用否定的前瞻性,并使用OR近似表示不支持的否定性的后裔。我修改了该示例,以解决我认为比较简单的问题。但是,我再次陷入困境。

('This is a <21>test</21> again.').split(/(?:(?!\\).|^)(<\/?(?:[1-9]|[1-4][0-9]|5[0-7])>)/) );

生成'This is a', '<21>', 'tes', '</21>', ' again.',因此,当不是<21>时,它不包括</21>\之前的字符。而且我知道为什么将?:用于非捕获。

但是,如果将其删除,则:

('This is a <21>test</21> again.').split(/((?!\\).|^)(<\/?(?:[1-9]|[1-4][0-9]|5[0-7])>)/) );

生成'This is a', ' ', '<21>', 'tes', 't', '</21>', ' again.',前一个字符生成一个单独的拆分。

除此问题外,转义的工作方式是,当前一个字符为\时,标记不会生成字符串的拆分。

能否让我知道是否有一种捕获前一个字符的方法,但是将其包含在前一个字符串的文本中,而不是其自身的拆分中?并且可能仅在\时排除它?

当字符串为'This is a <21>test</21> again.'时,期望的结果是 'This is a ', '<21>', 'test', '</21>', ' again.'

当它是'This is a \<21>test</21> again.'时,期望的结果是 'This is a <21>', 'test', '</21>', ' again.'

谢谢。

添加 在最近了解到在this MDN文档中使用正则表达式在replace操作中将内联函数用作参数之后,我开始怀疑是否可以在此处完成类似的操作。我对测量性能一无所知,但是下面Revo提供的正则表达式的复杂性以及他对我对效率的评论的回答表明,负面评价会大大提高效率并减少RegExp引擎的工作量,并且RegExp对我来说也是一个幕后黑匣子,促使我尝试另一种方法。它多了几行代码,但产生的结果相同,并且使用的正则表达式短得多。它真正要做的就是匹配带有或不带有转义符的标记,而不是尝试排除使用\进行转义的那些,然后在构建数组时忽略具有转义符的那些。下面的代码段。

我不知道控制台日志中提供的时间是否表示性能',但是,如果这样,在我运行的示例中,看来记录start和{{1 }}的百分比要比a.split和采用a.split方法对数组a的最终记录之间的百分比长得多。

此外,exec语句中最里面的if块在那里可以防止在标签位于字符串的开头或结尾时将while保存在数组中,或两个标签之间没有空格。

对于您为什么或为什么不使用一种方法优于另一种方法,或者在无法获得真正的负面观察的情况下引入更好的方法,我将不胜感激。谢谢。

""

1 个答案:

答案 0 :(得分:2)

您正在分割所需的子字符串,并使用捕获组将其包含在输出中。这也可能发生在不需要的子字符串上。您将它们匹配,并将它们包含在捕获组中,以将其输出。正则表达式为:

(undesired-part|desired-part)

不想要的子字符串的正则表达式应该放在首位,因为可以在其中找到所需的子字符串,即<21>中包含了\<21>,因此我们应该更早地匹配后者。

您已编写了所需的部分,而这对于我们是已知的:

(undesired-part|<\/?(?:[1-9]|[1-4]\d|5[0-7])>)

那不希望的呢?在这里:

(?:[^<\\]+|\\.?|<(?!\/?(?:[1-9]|[1-4]\d|5[0-7])>))+

让我们分解一下:

  • (?:非捕获组的开始
    • [^<\\]+匹配<\以外的任何内容
    • |
    • \\.?匹配转义字符
    • |
    • <(?!\/?(?:[1-9]|[1-4]\d|5[0-7])>)匹配不需要的<
  • )+ NCG结束,尽可能重复,至少重复一次

总的来说是

((?:[^<\\]+|\\.?|<(?!\/?(?:[1-9]|[1-4]\d|5[0-7])>))+|<\/?(?:[1-9]|[1-4]\d|5[0-7])>)

Js代码:

console.log(
  'This is a \\<21>test</21> ag<ain\\.'.split(/((?:[^<\\]+|\\.?|<(?!\/?(?:[1-9]|[1-4]\d|5[0-7])>))+|<\/?(?:[1-9]|[1-4]\d|5[0-7])>)/).filter(Boolean)
);