我想使用此正则表达式从多行字符串中删除前导和尾随空格:
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/