我再次在正则表达式方面苦苦挣扎。我一直在尝试使用转义字符来将自定义标签(例如<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
保存在数组中,或两个标签之间没有空格。
对于您为什么或为什么不使用一种方法优于另一种方法,或者在无法获得真正的负面观察的情况下引入更好的方法,我将不胜感激。谢谢。
""
答案 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)
);