gpt4 book ai didi

regex -/m 修饰符的 perl 正则表达式意外行为

转载 作者:行者123 更新时间:2023-12-04 14:55:22 26 4
gpt4 key购买 nike

我想使用此正则表达式从多行字符串中删除前导和尾随空格:

s/^\s*|\s*$//mg

在这个例子中它似乎或多或少地工作得很好:

perl -e '$_=" a \n \n b\n"; s/^\s*|\s*$//mg; print "$_\n";'

给出结果:

a
b

(没想到中间有空格的双\n变成了单\n)

但是看这个:

perl -e '$_=" a \n\n b\n"; s/^\s*|\s*$//mg; print "$_\n";'

结果:

ab

现在两个\n 都消失了,多行字符串现在是单行,这不是我想要的。如果这不是错误,我该如何避免这种行为?

最佳答案

使用 -Mre=debug 模块并深入研究细节,我找到了我认为的答案。我删除了前导空格,因为它与问题无关。除了相关部分,我删除了所有内容。两个正则表达式首先使用 RHS (5:BRANCH) 匹配第二个换行符前面的空格/换行符,然后在第二个换行符前面设置指针:

情况一:字符串a\n\n b\n

Matching REx "^\s+|\s+$" against "%n b%n"
4 <a %n > <%n b%n> | 0| 1:BRANCH(5)
4 <a %n > <%n b%n> | 1| 2:MBOL(3)
| 1| failed...
4 <a %n > <%n b%n> | 0| 5:BRANCH(9)
4 <a %n > <%n b%n> | 1| 6:PLUS(8)
| 1| POSIXD[\s] can match 2 times out of 2147483647...
6 <a %n %n > <b%n> | 2| 8:MEOL(9)
| 2| failed...
5 <a %n %n> < b%n> | 2| 8:MEOL(9)
| 2| failed...
| 1| failed...
| 0| BRANCH failed...
5 <a %n %n> < b%n> | 0| 1:BRANCH(5) <-- HERE!
5 <a %n %n> < b%n> | 1| 2:MBOL(3)
5 <a %n %n> < b%n> | 1| 3:PLUS(9)
| 1| POSIXD[\s] can match 1 times out of 2147483647...
6 <a %n %n > <b%n> | 2| 9:END(0)
Match successful!

在这种情况下,LHS (1:BRANCH) 首先失败,RHS (5:BRANCH) 失败,因此它向前移动 1 步,直到换行符之后,LHS 匹配,并删除前面的内容它:一个空间。

在换行符和 b 前面的空格之间的匹配中,当正则表达式中的“指针”向前移动到换行符前面时。

%n> < b%n>
^ \s

情况 2:字符串 a\n\n b\n

Matching REx "^\s+|\s+$" against "%n b%n"
3 <a %n> <%n b%n> | 0| 1:BRANCH(5) <-- HERE!
3 <a %n> <%n b%n> | 1| 2:MBOL(3)
3 <a %n> <%n b%n> | 1| 3:PLUS(9)
| 1| POSIXD[\s] can match 2 times out of 2147483647...
5 <a %n%n > <b%n> | 2| 9:END(0)
Match successful!

在这个字符串中,LHS(1:BRANCH)中的零宽度断言^可以看到字符串左边的换行符,并允许匹配。在另一个字符串中,它在那里有一个空格,因此无法匹配。所以 LHS 交流发电机匹配(称为 1:BRANCH),并删除它前面的内容,即换行符和空格 \n

与其像Case 1那样跳过第一次尝试向前移动1步,不如直接匹配左边的换行符,右边的空格\n :

%n> <%n b%n>
^ \s\s

TL;DR:在您的第二个字符串中,换行符可以匹配两个换行符之间的行首,因此将它们都删除。在第一个字符串中,它不能那样匹配,因为那里有一个空格,而是向前移动一步,跳过换行符并使用该换行符匹配字符串的开头。效果是换行符保留在字符串中。

如何避免这种行为?嗯,问题是你的正则表达式太松散了。 \n 可以以各种组合匹配正则表达式 ^$\s 的所有组件。它还可以匹配字符串的中间。如果您想要安全并获得可预测的结果,请以逐行模式使用正则表达式,不要将文件拖成单个字符串。那么你就不需要多行匹配了,所有的问题都迎刃而解。

否则,避免使用多行修饰符,只需照常删除前导和尾随空格,然后在字符串内部修剪多个带空格的换行符,如 s/\n\s*\n/\n/g.

本质上,您试图同时做太多事情。使您的正则表达式更严格,并尝试一次做一件事情。

关于regex -/m 修饰符的 perl 正则表达式意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68141141/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com