首页 文章

Perl - 正则表达式匹配双引号文本

提问于
浏览
2

需要一些正则表达式匹配的帮助 . 我正在尝试匹配一个双引号文本字符串,在一个大字符串中,它本身可以包含双引号对!这是一个例子:

"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

3 回答

  • 2

    改变这个:

    ".*?"
    

    对此:

    "(?>(?:[^"]+|"")*)"
    

    此外,您使用非贪婪匹配不是很安全 . 像这样的东西:

    \s+(.+?)   ## Variable name is never whitespace seperated
               ## Always underscored.  Akin to C variable names
    

    如果Perl发现这是匹配的唯一方法,那么最终可能会在变量名中包含空格 . (它会更喜欢在包含空格之前停止,但它不能保证 . )

    你应该经常检查以确保 m{} 找到了什么 . 如果您确定它始终匹配,那么您可以直接使用_2573006来验证它 .

  • 0

    我不知道你用自己的正则表达解析引用文本会有多少运气,这可能是相当冒险的事情 . 我会看一下像Text :: Balanced这样的模块 .

    https://metacpan.org/pod/Text::Balanced

    这也应该做你需要的东西,而且不那么痛苦 .

    我知道我应该按照要求回答这个问题,但是正则表达式真的不是你想要这样做的方式 .

  • 4

    我不确定这只是一个展示你的问题的例子,但这可以通过逐行阅读来解决:

    #!/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
    

    还要注意我已经指出你唯一的问题是 ".*?" 应该是 ".*" .

相关问题