是否有包含转义序列的字符串的纯正则表达式分割?

时间:2010-07-08 21:26:43

标签: regex perl split

给定一串管道分隔值(称为$psv),我希望能够通过这些管道进行拆分并填充数组。但是,该字符串还可以包含转义管道(\|)和转义转义符(\\),这两者都被视为仅仅是文字。我有几种解决方案可以解决这个问题:

  • 使用一些随机字符串替换两个转义序列 - 否则在$psvsplit(/\|/, $psv)中找到,替换回原始字符
  • 循环遍历$psv,逐个字符

我认为这两种方法都有效。但是对于最大的多巴胺泛滥,我想通过一次split()呼叫来做这件事,而不是别的。那么这是否有正则表达式?

4 个答案:

答案 0 :(得分:4)

您无需使用split执行此任务。另一种选择是:

my $psv = "aaa|bbb||ccc|\\|\\|\\||\\\\\\\\\\\\";
print "$psv\n";

my @words = map { s/\\([\\|])/$1/g; $_; } ($psv =~ /(?:^|\|) ((?:\\[\\|] | [^|])*)/gx);
printf("%s\n", join(", ", @words));

正则表达式可能看起来很可怕,但很容易解释。它匹配由管道分隔的每个单词。它从字符串的开头或管道分隔符开始。然后跟随任意数量的转义序列(\ + \|之一)或除管道之外的任意字符。

map中的正则表达式只是将转义序列替换为它们的真正含义。

答案 1 :(得分:4)

您是否需要纯正则表达式解决方案? (当然,除非这个问题更像是一个心理挑战,而不是一个实际问题)。

在实际代码中处理X分隔数据的正确方法是使用正确的解析器 - 一个非常常见的解析器是Text::CSV_XS(不要让名字欺骗你 - 它可以处理任何分隔符,而不是只是逗号)。它将正确处理转义,以及引用。

答案 2 :(得分:2)

如果Perl支持可变宽度的后视断言,你可以用这样的方式来做:

split(/(?<!(?<!\\)(?:\\\\)*\\)\|/, $psv);

这应该匹配一个前面没有的管道符号(奇数个反斜杠前面没有反斜杠)。但是只允许使用固定宽度的后视断言,所以这不是一个选项。有些正则表达式专家可能会想出一些实际上适合你的东西,但我个人认为有限状态机(一次循环$psv一个字符)可能是更好的选择。

我想你可以尝试的其他东西就是将字符串拆分为管道字符,然后检查结果列表的每个元素,看它是否以奇数个反斜杠结尾。如果是,请将它连接回列表的下一个元素,它们之间有|。基本上你会忽略转义序列进行拆分,然后返回并计算转义后的转义。

答案 3 :(得分:0)

更甜蜜的解决方案

此方法不使用拆分,但使用简单的正则表达式。


#!/usr/bin/perl -w

use strict;

   sub main{
      (my $psv = <DATA>) =~ s/\s+$//s;

      my @arr = $psv =~ /(?:^|\G\|)((?:[^\\|]|\\.)*)/sg;

      {
         local $" = ', ';      # $" - sets the pretty print
         print "@arr \n";      # outputs: abc, def, g\|i, jkl, m\|o, pqr, s\\u, v\w, x\\, , z 
      }

   }

   main();


__DATA__
abc|def|g\|i|jkl|m\|o|pqr|s\\u|v\w|x\\||z