你自己提供的
文档对我来说非常清晰。如果您能解释一下您理解上的问题以及您如何认为
/s
和
/m
是相反的,那会很有帮助。
简而言之,
/s
修改了点元字符
.
的行为,使其匹配任何字符。通常它匹配除换行符
"\n"
之外的任何字符,并且即使它包含换行符,它也将把字符串视为
单行。
/m
修改了插入符号
^
和美元符号
$
元字符,使它们在字符串
内部匹配换行符,将其视为
多行字符串。通常它们只会在字符串的开头和结尾匹配。
您不应该与
/g
修饰符混淆,因为它是“贪婪”的。它用于全局匹配,将在字符串中找到模式的
所有出现。术语“贪婪”通常用于模式
内部的限定词行为。例如,
.*
被称为贪婪,因为它将尽可能匹配尽可能多的字符,而不是
.*?
,它将匹配尽量
少的字符。
更新
在您修改后的问题中,您使用了
/".*"/mg
,其中
/m
是无关紧要的,因为如上所述,该修饰符仅改变
$
和
^
元字符的行为,在您的模式中没有这些元字符。
将其更改为
/".*"/sg
会稍微改善一下,因为
.
现在可以匹配每行末尾的换行符,因此该模式可以匹配多行字符串。 (请注意,这里考虑的是
对象字符串,即匹配只关心是否有换行符,就好像其中没有换行符一样。)然而,这里採取传统的
贪婪含义,因为该模式现在匹配从第一行第一个双引号到最后一行最后一个双引号之间的所有内容。我认为这不是您想要的。
有几种方法可以解决这个问题。我建议更改您的模式,使您想要的字符串是双引号,后跟任何字符序列(除了双引号),然后再跟一个双引号。这样写作
/"[^"]*"/g
(请注意,由于模式中现在没有点,因此不再需要
/s
修饰符),几乎可以实现您想要的效果,只是转义的双引号被视为结束模式。
看一下这个程序及其输出,注意我在每个匹配项的开头放了一个尖括号
>>
,以便它们可以区分开来。
use strict;
use warnings;
my $file = do {
local $/;
<DATA>;
};
my @strings = $file =~ /"[^"]*"/g;
print ">> $_\n\n", for @strings;
__DATA__
"This is string"
"1!=2"
"This is \"string\""
"string1"."string2"
"String"
"S
t
r
i
n
g"
输出
>> "This is string"
>> "1!=2"
>> "This is \"
>> ""
>> "string1"
>> "string2"
>> "String"
>> "S
t
r
i
n
g"
正如您所看到的,现在一切都井然有序,除了在"This is \"string\""
中它找到了两个匹配项,即"This is \"
和""
。修复这个问题可能比您想象的要复杂,但完全有可能。如果您也需要修复,请告诉我。
更新
我可能会将其完成。为了忽略转义的双引号并将它们视为字符串的一部分,我们需要接受任一\"
或除双引号外的任何字符。这是使用正则表达式交替运算符|
完成的,并且必须在非捕获括号(?: ... )
中进行分组。最终结果是/"(?:\\"|[^"])*"/g
(反斜杠本身必须转义,因此它被加倍),当放入上面的程序中时,会产生这个输出,我认为这就是您想要的。
>> "This is string"
>> "1!=2"
>> "This is \"string\""
>> "string1"
>> "string2"
>> "String"
>> "S
t
r
i
n
g"
m
修饰符只是意味着它将字符串识别为多行(用于匹配锚点^
和$
)。但不要过分解读名称“多行”和“单行”。它们是永远不应该存在的模式的糟糕名称。在Perl 6中,它们已被消除。 - Alan Moore/s
时,它会改变.
的行为,使得.
包含\n
作为.
的一部分。我的理解正确吗? - user2763829-0777
,它只适用于单行程序。我的解决方案是一个完整的程序,而do
块my $file = do {local $/; <DATA>; }
是读取整个文件的正确方式。OP也使用了相同的结构。我不能为每个可能缺乏知识的人提供解决方案。如果你不知道如何使用$/
,那么你需要认真学习一下。 - Borodinlocal $/
实际上等同于 -0777 对吧? - user15964