正则表达式s/\A\s*\n//
删除字符串开头的所有空白行。它保留所有其他内容,包括第一个可见行开头的所有空白。所谓“可见行”,我指的是满足/\S/
的行。下面的代码演示了这一点。
但它是如何工作的呢?\A
定位字符串的开头\s*
贪婪地抓取所有的空白。但是如果没有(?s)
修饰符,它应该停在第一行的末尾,不是吗?请参阅https://perldoc.perl.org/perlre。
假设没有(?s)
修饰符,它仍然“将字符串视为一行”,那么我会认为贪婪的\s*
会抓取它看到的每一个空格字符,包括换行符,所以它会传递“dogs”字符串前面的换行符,继续抓取空格,遇到“d”,我们永远不会得到匹配。
尽管如此,这段代码确实做到了我想要的。因为我无法解释它,它就像是一个拼凑的东西,通过尝试和错误发现它碰巧工作了。它工作的原因是什么?
#!/usr/bin/env perl
use strict; use warnings;
print $^V; print "\n";
my @strs=(
join('',"\n", "\t", ' ', "\n", "\t", ' dogs',),
join('',
"\n",
"\n\t\t\x20",
"\n\t\t\x20",
'......so what?',
"\n\t\t\x20",
),
);
my $count=0;
for my $onestring(@strs)
{
$count++;
print "\n$count ------------------------------------------\n";
print "|$onestring|\n";
(my $try1=$onestring)=~s/\A\s*\n//;
print "|$try1|\n";
}
2条答案
按热度按时间qkf9rpyu1#
但它是如何工作的呢?
...
我认为贪婪的\s* 会抓取它看到的每一个空格字符,包括换行符,所以它会传递“dogs”字符串前面的换行符,继续抓取空格,遇到“d”,我们永远不会得到匹配。
正确--
\s*
首先抓取d
(在dogs
中)之前的所有内容,这样匹配就会失败......所以它会备份,一次一个字符,缩短贪婪的抓取,以便给后面的模式(这里是\n
)提供匹配的机会。这样就成功了!所以
\s*
匹配到(最后一个!)\n
,这个匹配到模式中的\n
,一切都很好。这个被删除了,我们保留了打印出来的"\tdogs"
。回溯可以被抑制,最明显的是通过所有格形式(如
\w++
等),或者更确切地说是通过扩展构造(?>...)
。但是如果没有(?s)修饰符,它应该停在第一行的末尾,不是吗?
这里您可能会混淆
\s
与.
,后者实际上与\n
不匹配(没有/s
)nmpmafwu2#
这里有两个问题。
第一个是关于
\s
和(缺乏)(?s)
的相互作用。很简单,没有相互作用。\s
匹配空格字符,包括换行符(LF)。它不受(?s)
的任何影响。(?s)
只会影响.
。(?-s)
使.
匹配除LF以外的所有字符。[默认值](?s)
使.
匹配所有字符。如果要匹配当前行上的空白,可以使用
\h
代替\s
。它只匹配水平空白,因此不包括CR和LF(以及其他)。或者,
(?[ \s - \n ])
[1]、[^\S\n]
[2]和\s(?<!\n)
[3]都匹配除LF以外的空白字符。第二个是关于贪婪的误解。
贪婪或缺乏贪婪不会影响模式是否匹配,只会影响它匹配什么。例如,对于给定的输入,
/a+/
和/a+?/
都匹配,或者都不匹配。不可能一个匹配而另一个不匹配。当某个东西是贪婪的,它意味着它将在当前位置 * 匹配最有可能的东西,这允许整个模式匹配 *。
这个模式可以通过让
.*
只匹配cccc
而不是ccccd
来进行匹配,因此这样做了。这是通过回溯来实现的。.*
最初匹配ccccd
,然后发现d
不匹配,因此.*
只尝试匹配cccc
。这允许匹配d
,从而匹配整个模式。你会发现回溯也在贪婪之外使用。
"efg" =~ /^(e|.f)g/
匹配是因为当它在使用第一个选择时无法匹配g
时,它会尝试第二个选择。与前面示例中
.*
避免匹配d
的方式相同,您的示例中\s*
避免匹配dog
之前的LF和制表符。1.在5.36之前需要
use experimental qw( regex_sets );
,但从5.18开始可以安全使用,因为它作为一个实验性功能引入后被接受,没有任何变化。1.不太清楚,因为它使用双重否定。
[^\S\n]
=一个字符,该字符为(not(not(\s)或LF))
=一个字符,该字符为(not(not(\s))且不是(LF))
=一个字符(\s而不是LF)
1.效率较低,而且远不如正则表达式集漂亮。