正则表达式:如果原始字符串与某些过滤器匹配,如何替换另一个字符串中所有出现的字符串
regex: how to replace all occurrences of a string within another string, if the original string matches some filter
- 如果原始字符串匹配某些过滤器,我需要替换另一个字符串中出现的所有字符串
- 我只能通过
s
命令使用单个正则表达式,因为我需要将组装好的命令发送给第三方 API
我曾尝试使用正向预测来不消耗我想要替换字符的字符串,但不知何故我无法按预期进行替换。
这是我到目前为止所做的尝试以及结果:
(请注意过滤器 - 这里 [0-9]+
只是一个示例,将从调用站点传入,我不能直接影响它。
预期结果: 9999997890
perl -e '$x = "4564567890"; $x =~ s/(?=^[0-9]+$)456/999/g; print $x'
实际结果: 9994567890
- 这仅替换第一次出现的
456
。为什么会这样?
- 我更难理解的是,如果我将过滤器前瞻更改为
(?=.*)
,则 456 的两次出现都将被替换。为什么更改过滤器会对正则表达式的替换部分产生任何影响?
我似乎遗漏了一些关于如何在一个 s
命令中混合过滤和替换内容的非常基本的要点。
您的正则表达式仅替换仅由数字组成的字符串开头的 456
。
您可以使用
s/(?:\G(?!^)|^(?=\d+$))\d*?\K456/999/g
图案详情
(?:\G(?!^)|^(?=\d+$))
- 匹配上一个成功匹配的结尾 (\G(?!^)
) 或 (|
) 字符串开头 (^
) 的自定义边界仅包含数字 ((?=\d+$)
)
\d*?
- 0+ 位,但越少越好
\K
- 省略当前匹配的字符
456
- 456
子串。
想法是:
- 使用基于
\G
的模式预验证字符串:(?:\G(?!^)|^(?=<YOUR_VALID_LINE_FORMAT>$))
- 然后在上述之后调整消费模式。
或者,您可以使用 (*SKIP)(*F)
来跳过不仅仅由数字组成的字符串。
s/^\d*\D.*(*SKIP)(*F)|456/999/g
See this demo at regex101 or your demo at tio.run
左侧部分 ^\d*\D.*
尝试匹配任何 \D
非数字 。如果找到,则跳过 .*
字符串的其余部分并失败 |
或匹配指定的子字符串 456
.
- 如果原始字符串匹配某些过滤器,我需要替换另一个字符串中出现的所有字符串
- 我只能通过
s
命令使用单个正则表达式,因为我需要将组装好的命令发送给第三方 API
我曾尝试使用正向预测来不消耗我想要替换字符的字符串,但不知何故我无法按预期进行替换。
这是我到目前为止所做的尝试以及结果:
(请注意过滤器 - 这里 [0-9]+
只是一个示例,将从调用站点传入,我不能直接影响它。
预期结果: 9999997890
perl -e '$x = "4564567890"; $x =~ s/(?=^[0-9]+$)456/999/g; print $x'
实际结果: 9994567890
- 这仅替换第一次出现的
456
。为什么会这样? - 我更难理解的是,如果我将过滤器前瞻更改为
(?=.*)
,则 456 的两次出现都将被替换。为什么更改过滤器会对正则表达式的替换部分产生任何影响?
我似乎遗漏了一些关于如何在一个 s
命令中混合过滤和替换内容的非常基本的要点。
您的正则表达式仅替换仅由数字组成的字符串开头的 456
。
您可以使用
s/(?:\G(?!^)|^(?=\d+$))\d*?\K456/999/g
图案详情
(?:\G(?!^)|^(?=\d+$))
- 匹配上一个成功匹配的结尾 (\G(?!^)
) 或 (|
) 字符串开头 (^
) 的自定义边界仅包含数字 ((?=\d+$)
)\d*?
- 0+ 位,但越少越好\K
- 省略当前匹配的字符456
-456
子串。
想法是:
- 使用基于
\G
的模式预验证字符串:(?:\G(?!^)|^(?=<YOUR_VALID_LINE_FORMAT>$))
- 然后在上述之后调整消费模式。
或者,您可以使用 (*SKIP)(*F)
来跳过不仅仅由数字组成的字符串。
s/^\d*\D.*(*SKIP)(*F)|456/999/g
See this demo at regex101 or your demo at tio.run
左侧部分 ^\d*\D.*
尝试匹配任何 \D
非数字 。如果找到,则跳过 .*
字符串的其余部分并失败 |
或匹配指定的子字符串 456
.