我如何捕获逃脱的“但不是未转义的”?

时间:2010-02-01 06:18:55

标签: regex perl

假设需要由正则表达式捕获的部分由以下字符串中的PORTION指示

,"PORTION","","a",["some_string"]  

PORTION的例子是

  • \“ABC123
  • abc123 \“
  • \ “ABC123 \”
  • ABC \ “123 \”
  • ABC123

所以字符串实际上看起来像

  • ,“\”abc123“,”“,”a“,[”some_string“]
  • ,“abc123 \”“,”“,”a“,[”some_string“]
  • “\”abc123 \“”,“”,“a”,[“some_string”]
  • “abc \”123 \“”,“”,“a”,[“some_string”]
  • “abc123”,“”,“a”,[“some_string”]

PORTION被双引号括起来。 PORTION中的双引号由反斜杠转义。我目前的模式是

my $pattern = '(.?([\\"]|[^"][^,][^"])*)';

产生上述例子的结果如下

  • \ “ABC123”, “”, “一个”
  • ABC123
  • \“ABC12
  • ABC \ “123 \”“
  • ABC123"

模式尝试匹配不是“,”的序列前面的所有内容 并且还允许捕获\“ 但它没有按预期工作。 我怎样才能使它发挥作用?

6 个答案:

答案 0 :(得分:5)

你太复杂了;没有规则说你必须在一个单片正则表达式中进行所有解析。由于您的字符串看起来像逗号分隔的序列,因此首先将其解析为:

my @fields = split /(?<!\\),/, $string;   # use comma as a delimiter (except when escaped)

...然后相应地解析你的第一个字段:

shift @fields unless $fields[0];     # pull off the potentially null first field
$fields[0] =~ s/^"//g;               # remove the leading "
$fields[0] =~ s/(?<!\\)"$//g;        # remove the trailing " that isn't preceded by a \

您可以通过将上述代码包装在for循环或map()中来解析所有字段。

请注意,此代码不会考虑\\,这样的事件(逗号在此处是有效的分隔符,即使它将错误地通过正则表达式)。因此,最好为您的格式使用适当的解析器(无论它是什么)。您可能需要查看Text::CSV

答案 1 :(得分:3)

只需使用Text::CSV

即可

答案 2 :(得分:1)

您的问题需要臭名昭着的零宽度负面后卫断言

...可让您匹配关注foo的{​​{1}}。

文档在这里:http://perldoc.perl.org/perlre.html#Extended-Patterns

你想在你的正则表达式中使用这样的东西:

bar

匹配双引号,尽可能少的任何字符,然后另一个双引号前面没有反斜杠(我认为通过加倍逃脱)。第一组parens按照你的意图捕获,第二个括号没有捕获。

修改:同时使用http://www.internetofficer.com/seo-tool/regex-tester/进行测试 它似乎工作正常。

编辑:正如outis指出的那样,此表达式将无法正确匹配一个PORTION,其中结束引号之前的最后一个字符是转义反斜杠。如果您没有预料到文本中的反斜杠,那么您应该没问题。

答案 3 :(得分:1)

不要忘记允许转义的反斜杠和转义引号。使用RE匹配平衡的任何东西都会变得很难看:

/(?<=")((?:[^"\\]+|\\+[^"\\]|(?:\\\\)+|(?<!\\)\\(?:\\\\)*")*)(?=")/

像以太一样,帮自己一个忙,并使用解析器。

答案 4 :(得分:0)

如果您的数据以逗号分隔并且没有嵌入的逗号,只需拆分“,”并获取相应的字段

while(<>){
    chomp;
    @s = split /,/;
    if ($s[0] eq ""){
        print "$s[1]\n";
    }else{
        print $s[0]."\n";
    }
}

输出

$ perl perl.pl file
"\"abc123"
"abc123\" "
"\"abc123\""
"abc\"123\""
"abc123"

答案 5 :(得分:0)

如果你需要考虑outis提到的转义反斜杠,你可以使用:

m/"((\\\\|\\"|[^"])+)"/

(似乎我不能对outis的答案发表评论,但outis解决方案不适用于此:

"abc\\\"123"

将产生

abc\\\

输入:

,"\"abc123","","a",["some_string"]
,"abc123\" ","","a",["some_string"]
"\"abc123\"","","a",["some_string"]
"abc\"123\"","","a",["some_string"]
"abc123","","a",["some_string"]
"ab\\c123","","a",["some_string"]
"abc123\\","","a",["some_string"]
"abc123\\\"","","a",["some_string"]
"abc\\\"123\"","","a",["some_string"]
"abc123\\\\\"","","a",["some_string"]

输出:

\"abc123
abc123\" 
\"abc123\"
abc\"123\"
abc123
ab\\c123
abc123\\
abc123\\\"
abc\\\"123\"
abc123\\\\\"