Regex 在两个标记中的任意位置匹配单词,由空格或标记分隔

Regex 在两个标记中的任意位置匹配单词,由空格或标记分隔,regex,sed,Regex,Sed,使用Gnused,仅当单词出现在两个标记之间(但在它们之间的任何位置)时,我才能替换该单词,前提是该单词左侧由起始标记或空格分隔,右侧由结束标记或空格分隔?非常类似于在单词的任一侧(标记之间)使用\b,但仅允许空白(如果与起始/结束标记相邻,则不允许空白)作为分隔符\b标记“单词”和“非单词”字符之间的边界,并将-视为非单词字符,这在本例中是不需要的。到目前为止的工作和结果,以及下面的测试用例 [详细信息:具体来说,我正试图用其他类替换HTML文件中class=“…”文本中的类。这可能是另一个“

使用Gnu
sed
,仅当单词出现在两个标记之间(但在它们之间的任何位置)时,我才能替换该单词,前提是该单词左侧由起始标记或空格分隔,右侧由结束标记或空格分隔?非常类似于在单词的任一侧(标记之间)使用
\b
,但仅允许空白(如果与起始/结束标记相邻,则不允许空白)作为分隔符
\b
标记“单词”和“非单词”字符之间的边界,并将
-
视为非单词字符,这在本例中是不需要的。到目前为止的工作和结果,以及下面的测试用例

[详细信息:具体来说,我正试图用其他类替换HTML文件中
class=“…”
文本中的类。这可能是另一个“不要使用正则表达式处理HTML”的例子,但问题就这样被控制住了(例如,我不在乎它是否与开始标记外部匹配;我不在乎嵌套),感觉它应该是可能的,如果可能的话,它会比我的下一个选项Jsoup(无论多么酷和诱人)更受欢迎。而且感觉它像一个正则表达式和/或
sed
学习机会。]

起始标记是:

\(\sclass\s*=\s*"\) " 以下是我到目前为止所做的,将
spanN
更改为
col-md-N
(但使用
\b
,因此无法正常工作):

s/\(\sclass\s*=\s*“\)\([^”]*\)\bspan\([0-9]\+\)\b\([^”]*\)“/\1\2col md-\3\4”/g 它对这个示例数据非常有效:

这里面有span3
这里面有三个
这里面有三个
给我想要的:

这里面有span3
这里面有三个
这里面有三个
当然,这也会改变以下情况:

这里面有x-span3
这里面有x-span3
这里面有x-span3
这里面有span3-x
这里面有span3-x
这里面有span3-x
…这是不需要的。不用说,
xxxspan3
也应该单独处理(当然,
\b
版本就是这样做的)

有没有可能使它不改变这些?对于“在开头”、“在中间”和“在结尾”的情况,不重复表达三次?(六次,如果你计算单引号排列。几十次,如果你计算所有其他我需要改变的。)

如果答案真的是“不,你不能”,那么,这是一个完全可以接受的答案,我会得到一个更大的锤子



结语:仅供参考,这确实是另一个“不要试图用正则表达式处理HTML”的案例。“虽然Jerry的回答确实满足了我的需要,但我越深入了解它,就越清楚我需要比regex能提供的更多的上下文。我最终在
cheerio
DOM解析器中使用了NodeJS,因为
cheerio
非常擅长最小化对标记的更改。

您可以尝试这个regex:

s/\(\sclass\s*=\s*"\)\(\([^"]*\)\( \)\)\?span\([0-9]\+\)\(\( \)\([^"]*\)\)\?"/\1\3\4col-md-\5\7\8"/g
[抱歉,这是一个很大的长条]

我从(突出显示的变化)开始:

我试图捕获
"
span
之前的空格,以及
span
中数字后面的两个空格中的任何一个。这也要求在替换中添加更多的反向引用,并删除必须调整正则表达式的最后一个引号,但由于
class=span
没有资格通过,我意识到我不能通过不要将第一个引号设为可选或删除最后一个引号

因此,我删除了捕获组中的引号:

s/\(\sclass\s*=\s*"\)\([^"]*\)\( \)span\([0-9]\+\)\(" \)\([^"]*\)"/\1\2\3col-md-\4\5\6"/g
                              ^^^^^                ^^^^^
s/\(\sclass\s*=\s*"\)\(\([^"]*\)\( \)\)\?span\([0-9]\+\)\(\( \)\([^"]*\)\)\?"/\1\3\4col-md-\5\7\8"/g
                                                                                ^^^^         ^^^^
现在,只有引号需要处理。因为我们只能有
“span…
span\d+”
,这意味着中间的一切都可以选择:

s/\(\sclass\s*=\s*"\)\(\(\([^"]*\)\( \)\)\?span\([0-9]\+\)\(\(" \)\([^"]*\)\)\?"/\1\2\3col-md-\4\5\6"/g
                     ^^                ^^^^               ^^               ^^^^
唯一剩下的就是调整不同捕获组的反向引用:

s/\(\sclass\s*=\s*"\)\([^"]*\)\( \)span\([0-9]\+\)\(" \)\([^"]*\)"/\1\2\3col-md-\4\5\6"/g
                              ^^^^^                ^^^^^
s/\(\sclass\s*=\s*"\)\(\([^"]*\)\( \)\)\?span\([0-9]\+\)\(\( \)\([^"]*\)\)\?"/\1\3\4col-md-\5\7\8"/g
                                                                                ^^^^         ^^^^

您是否希望将此命令保留为一个命令,并且仅使用
sed
命令?@C.B.:理想情况下::-)对于正在进行的各种更改以及双引号和单引号版本,我已经必须重复这些命令。因此,大量的排列(无论是单独的命令还是笨拙的替换)可能会将其推向“以不同的方式进行”的领域……怎么样?(我只需要在最后一个被否定的类中添加一个
,这样匹配就不会流到其他行上。你可以忽略这个字符)。这真是太棒了,谢谢你们的正则表达式和解释。对于稍后出现的任何人,这不会同时处理
spanN
stuff here中的
s,它只处理最后一个。这对我来说很好,在同一个元素上不应该有两个,但是如果你在其他地方应用这个,它可能对你不起作用。它确实能正确处理
这里面有span3这里面有span6。很棒的东西。
s/\(\sclass\s*=\s*"\)\(\([^"]*\)\( \)\)\?span\([0-9]\+\)\(\( \)\([^"]*\)\)\?"/\1\3\4col-md-\5\7\8"/g
                                                                                ^^^^         ^^^^