换句话说,在匹配结束和第二个模式之间不能出现其他模式,这需要在单个正则表达式中实现。
在我的具体案例中,我有一个HTML页面,需要提取其中的所有内容
<w-block-content><span><div>
以及
</div></span></w-block-content>
其中
- 元素可能具有属性
- HTML可能已格式化或未格式化-可能有额外白色和换行符
- 在上述任何标记之间可能存在其他内容,包括上述外部
div
中的内部div
元素。 - 仅包含一个直接子项
<span>
子项(即,它可以包含其他非跨范围子项) - 它只包含一个直接
<div>
子级 - 它 Package 了必须提取的内容
- 🚩匹配必须一直延伸到X1 M7 N1 X内的X1 M6 N1 X内的最后一个X1 M5 N1 X,即使它与开始的X1 M8 N1 X不匹配。
- 解决方案必须是纯ECMAScript规范正则表达式。不能使用Javascript代码
因此,问题在顶部的问题中陈述。
只要没有内部</div>
标记,* 以下正则表达式就能成功匹配:*
(?:<w-block-content.*[\s\S]*?<div>)([\s\S]*?)(?:<\/div>[\s\S]*?<\/span>[\s\S]*?<\/w-block-content>)
但是如果有额外的</div>
标签,匹配会提前结束,而不包括整个块。
我使用[\s\S]*?
来匹配任意内容,包括多余的空格和换行符。
以下是示例测试数据:
</tr>
<td>
<div draggable="true" class="source master draggable-box wysiwyg-block" data-block-type="master" data-block-id="96e80afb-afa0-4e46-bfb7-34b80da76112" style="opacity: 1;">
<w-block-content data-block-content-id="96e80afb-afa0-4e46-bfb7-34b80da76112"><span class="source-block-tooltip">
<div>
Další master<br><div><b>Master č. 2</b> </div><br>
</div>
</span></w-block-content>
</div>
</td>
</tr>
</tr>
<td>
<div draggable="true" class="source master draggable-box wysiwyg-block" data-block-type="master" data-block-id="96e80afb-afa0-4e46-bfb7-34b80da76112" style="opacity: 1;">
<w-block-content data-block-content-id="96e80afb-afa0-4e46-bfb7-34b80da76112"><span class="source-block-tooltip">
<div>
Další master<br><b>Master č. 2</b><br>
</div>
</span></w-block-content>
</div>
</td>
</tr>
我一直在测试(https://regex101.com/r/jekZhr/3
第一个提取的块应为:
Další master<br><div><b>Master č. 2</b> </div><br>
我知道regex不是处理XML/HTML的最佳工具,但我需要知道这样的regex是否可行,或者我是否需要更改数据的结构。
5条答案
按热度按时间rkttyhzu1#
正如已经评论过的,regex不是一个通用的工具--事实上它是一个匹配字符串中模式的特定工具。已经说过,这里有一个regex解决方案,它将匹配第一个
<div>
之后直到</w-block-content>
的所有内容。从那里找到</div>
和.slice()
的最后一个索引。后面一看:
(?<=
...)
必须在匹配之前,但不会包含在匹配本身中。展望未来:
(?=
...)
必须继续进行匹配,但不会包含在匹配本身中。| 节段|说明|
| - ------| - ------|
|
|找出文字"
<w-block-content
",然后是任何内容,然后是文字"<div
",然后是任何内容,然后是文字">
"是否在匹配的内容之前。不要将其包括在匹配中。||
|匹配任何内容|
|
|查找文字"
</w-block-content>
"是否在匹配的文字之后。不要将其包含在匹配中。|1hdlvixo2#
在你的模式中,你使用
[\s\S]*?
匹配任何字符,尽可能少的匹配,但是当你在元素之间使用那个部分时,模式可以回溯并允许匹配第一个</div>
如果您想要提取匹配的部分,并且您已经有了使用捕获组的模式 "只要没有内部标记",则不需要任何查找。
您可以使您的模式更具体,并匹配开始和结束标记,仅在它们之间使用可选的空白字符。
<w-block-content[^<>]*>\s*
匹配w-block-content
元素,其中[^<>]*
是一个取反的字符类,它匹配<
和>
以外的可选字符,\s*
匹配可选的空白字符(包括换行符)<span[^<>]*>\s*
与span
相同<div[^<>]*>
与div
相同([^]*?)
捕获组1,匹配包括换行符在内的任何字符,尽可能少<\/div>\s*<\/span>\s*<\/w-block-content>
匹配结束部分,结束标记之间可以有可选的空白字符。参见regex demo。
See why parsing HTML with a regex is not advisable
ccrfmcuu3#
纯正则表达式解决方案,接受比问题中提供的示例数据更复杂的输入。
底部的代码和数据片段包含了这样的复杂输入,例如,它在匹配元素中包含了额外的(意外的)非空白,而这些元素不是提取数据的一部分,在本例中是HTML注解。
🚩 我从问题中提供的原始正则表达式推断出这是一个要求。
在撰写本文时,没有其他答案可以处理此输入。
⚠️ It also accepts some illegal input, but that's what you get by requiring the use of regular expressions and disallowing a true HTML parser.
另一方面,HTML解析器将使处理问题中给出的示例输入中格式错误的HTML变得困难。符合规范的解析器将通过强制将标记与树中更靠上的打开的
div
匹配来处理这种"标记汤",从而过早地关闭沿途的任何中间父元素。因此,它不仅将对数据记录使用第一个而不是最后一个</div>
,它可能关闭更高的容器元素,并对如何解析文件的其余部分造成严重破坏。正则表达式
正则表达式满足问题中所述的所有要求:
String.matchAll()
在一次调用中调用它(返回匹配的数组)Regexp.exec()
迭代地调用它来迭代地解析记录,Regexp.exec()
在每次调用时返回连续的匹配,自动跟踪它停止的位置。此外:
dotall
正则表达式解释了
|
/
||| - ------| - ------|
|
<w-block-content[^>]*>
|使用任意属性和空格打开w-block-content
"record"标记||
[\s\S]*?
|w-block-content
内span
之前的任意空白和非空白|| x1米11米1x|应为具有任意属性和空白的嵌套
span
||
[\s\S]*?
|span
内div
之前的任意空白和非空白||
<div[^>]*>
|应为具有任意属性和空白的嵌套div
。此div
Package 数据。||
([\s\S]*?)
|所述数据|| x1米20英寸1x|带有任意合法空格的结束
div
标记。||
(?:(?!<\/div\s*>)[\s\S])*?
| arbitrary whitespace and non-whitespace withinspan
afterdiv
🌶 except that it guarantees that</div>
matched by the preceding pattern is the last one within thespan
element. ||
<\/span\s*>
|带有任意合法空格的结束span
标记。||
[\s\S]*?
|span
之后w-block-content
内的任意空白和非空白||
<\/w-block-content\s*>
|带有任意合法空格的结束w-block-content
标记。||
/g
|global
标志,允许从输入中提取多个匹配项。影响String.matchAll
和RegExp.exec
的工作方式。|棘手的测试数据和示例用法/测试代码
ehxuflar4#
下面是适用于the example you provided的正则表达式;为了清晰起见,我把它分成了三行,也许你会把它们合并成一行:
我认为在这种情况下不需要使用捕获组
()
,如果使用look-behind(?<=)
和look-ahead(?=)
进行边界查找(两者都是非捕获的),那么可以让整个匹配成为您想要查找的内容。我添加这个答案是因为我没有看到其他答案使用
[^>]
(= negated character class)来允许标签字符串在接受附加属性时是开放式的,而不完全跳过标签闭包的任何强制,我认为这是一种更干净、更安全的方法。我承认我不是一个JavaScript爱好者,所以:今天我了解到JavaScript正则表达式匹配不支持单行模式(
/s
),因此您必须将[\s\S]
作为一种解决方案,而不仅仅是.
。tquggr8v5#
下面的解决方案假设在目标
</div>
和</span>
之间只能有空格和/或换行符,这是从OP的声明中得出的,即<span>
只有一个直接子对象,这就是我们要查找其内容的 Package 器<div>
:https://regex101.com/r/sn0frx/1
EDIT:explanation.这基本上是OP的正则表达式,但有以下更改:
1.在模式的
<\/div>
之后插入负前瞻((?!<\/div>))*
以忽略任何较早的</div>
。\S
,所以现在是[\s]*?
,基于上述假设。1.类似地,对
<\/span>
后面的字符类进行了相同的编辑,这是基于我们正在查找的</span>
是</w-block-content>
前面的字符类的假设,尽管有空格和换行符,如问题所示。