请在正则表达式匹配方面寻求帮助。我正在尝试匹配一个双引号文本字符串,在一个大字符串中,它本身可以包含双引号对!这是一个例子:
"Please can ""you"" match this"
我的问题的更全面的例子和我到目前为止的地方如下所示。下面的代码只在哈希中正确存储'paris',伦敦和墨尔本都不正确,因为双引号对很早就终止了长描述。
任何帮助都非常感激。
use strict;
use warnings;
use Data::Dumper;
my %hash;
my $delimiter = '/begin CITY';
local $/ = $delimiter;
my $top_of_file = <DATA>;
my $records=0;
while(<DATA>) {
my ($section_body) = m{^(.+)/end CITY}ms;
$section_body =~ s{/\*.*?\*/}{}gs; # Remove any comments in string
$section_body =~ m{ ^\s+(.+?) ## Variable name is never whitespace seperated
## Always underscored. Akin to C variable names
\s+(".*?") ## The long description can itself contain
## pairs of double quotes ""like this""
\s+(.+) ## Everything from here can be split on
## whitespace
\s+$
}msx;
$hash{$records}{name} = $1;
$hash{$records}{description} = $2;
my (@data) = split ' ', $3;
@{ $hash{$records} }{qw/ size currency /} = @data;
++$records;
}
print Dumper(\%hash);
__DATA__
Some header information
/begin CITY
london /* city name */
"This is a ""difficult"" string to regex"
big
Sterling
/end CITY
/begin CITY paris
"This is a simple comment to grab."
big
euro /* the address */
/end CITY
/begin CITY
Melbourne
"Another ""hard"" long description to 'match'."
big
Dollar
/end CITY
答案 0 :(得分:4)
改变这个:
".*?"
到此:
"(?>(?:[^"]+|"")*)"
此外,您使用非贪婪匹配不是很安全。像这样:
\s+(.+?) ## Variable name is never whitespace seperated
## Always underscored. Akin to C variable names
如果Perl发现这是匹配的唯一方法,最终可能会在变量名中包含空格。 (它会更喜欢在包含空格之前停止,但它不能保证。)
你应该经常检查以确保m{}
找到了什么。如果您确定始终匹配,那么您只需点击or die
即可验证。
答案 1 :(得分:2)
我不知道你用自己的正则表达解析引用文本会有多大的运气,这可能是非常冒险的事情。我会看一下像Text :: Balanced这样的模块。
https://metacpan.org/pod/Text::Balanced
这也应该做你需要的东西,而且不那么痛苦。
我知道我应该按照要求回答这个问题,但是正则表达式真的不是你想要这样做的方式。
答案 2 :(得分:0)
我不确定这只是一个展示你的问题的例子,但这可以通过逐行阅读来解决:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hash;
my $delimiter = '/begin CITY';
local $/ = $delimiter;
my $top_of_file = <DATA>;
my $records=0;
my @lines;
sub trim
{
my $string = shift;
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
while(<DATA>) {
my ($section_body) = m{^(.+)/end CITY}ms;
$section_body =~ s{/\*.*?\*/}{}gs; # Remove any comments in string
$section_body =~ s{^\s*\n}{}gs; # Remove empty lines
#################
if ($section_body =~ m{".*"}) { # Or a normal greedy match
$hash{$records}{quoted} = $&;
}
#################
@lines = split "\n", $section_body, 5;
$hash{$records}{name} = trim($lines[0]);
$hash{$records}{description} = trim($lines[1]);
$hash{$records}{size} = trim($lines[2]);
$hash{$records}{currency} = trim($lines[3]);
++$records;
}
print Dumper(\%hash);
__DATA__
Some header information
/begin CITY
london /* city name */
"This is a ""difficult"" string to regex"
big
Sterling
/end CITY
/begin CITY paris
"This is a simple comment to grab."
big
euro /* the address */
/end CITY
/begin CITY
Melbourne
"Another ""hard"" long description to 'match'."
big
Dollar
/end CITY
另请注意,我已经指出您唯一的问题是".*?"
可能应该是".*"
。