Perl 重复分隔符(逗号)的分割问题

psm*_*023 3 regex perl split

我有重复分隔符(逗号)的问题

字符串输入

abc : {A=[2, 2, 2], B=x, C=[1, 1, 1, 1], D=1}
Run Code Online (Sandbox Code Playgroud)

我的代码

if ($_ =~ /^(\w+)\s+:\s+\{(\S+=.*)\}/)
{
  my $attr_struct = $1; 
  my $sub_attr_struct = $2;
  $sub_attr_struct =~ s/,\s+/,/g;
  my @sub_attr_struct_split = split(',',$sub_attr_struct);
  foreach my $attr (@sub_attr_struct_split)
   {
    print "$attr_struct".".$attr\n";  
   }
 }
Run Code Online (Sandbox Code Playgroud)

预期输出是

abc.A=2:2:2
abc.B=x
abc.C=1:1:1:1 
abc.D=1
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 5

split当逗号是要获取的字段的一部分时,很难使用逗号;分隔符模式需要一个复杂的正则表达式,这对于各种数据来说是脆弱的。\xe2\x80\xa0

\n

相反,一种方法

\n
my ($w, $c) = /(\\w+) \\s+:\\s+ { (.+) }/x; \n\nmy @t = $c =~/ ([^=]+ = (?:\\[ [^\\]]+ \\] | \\w+) ) (?:,\\s+)? /gx; \n\ns/,\\s+/:/g for @t;\n
Run Code Online (Sandbox Code Playgroud)\n

在命令行程序中,用于准备测试驱动

\n
perl -wE\'$_=q(abc : {A=[2, 2, 2], B=x, C=[1, 1, 1, 1], D=1}); \n    say; say"-"x40;\n    ($w, $c) = /(\\w+) \\s+: \\s+{ (.+) }/x; \n    say $w; \n    @t = $c =~/ ([^=]+ = (?:\\[ [^\\]]+ \\] | \\w+) ) (?:,\\s+)? /gx;\n    s/,\\s+/:/g for @t;\n    say for @t \'\n
Run Code Online (Sandbox Code Playgroud)\n

可以压缩在一个正则表达式中,但我绝对同意首先将其分解的问题。

\n

它打印

\n
abc : {A=[2, 2, 2], B=x, C=[1, 1, 1, 1], D=1}\n----------------------------------------\nabc\nA=[2:2:2]\nB=x\nC=[1:1:1:1]\nD=1\n
Run Code Online (Sandbox Code Playgroud)\n

可以形成精确的所需输出:

\n
my @terms = map { "$w.$_" } @t;\n
Run Code Online (Sandbox Code Playgroud)\n
\n

评论

\n
    \n
  • 首先将输入拆分为单词(之前:)和以下花句的内容。

    \n
  • \n
  • 然后在花式匹配中:所有直到=,然后=,然后[...]或者单词字符(x1,等等)。

    \n
  • \n
  • 匹配/g对整个字符串进行全局 ( ) 运行,返回所有此类模式。但中间的内容, 是可选的 ( (?,\\s+)?),因为最后一项后面没有跟随它。

    \n
  • \n
  • =实际数据中还能看出什么?

    \n
  • \n
  • 使用否定字符类 ( [^=]+, [^\\]]+) 提供非贪婪匹配,因为这些模式匹配序列直到该字符第一次出现。

    \n
  • \n
  • 表达式s/,\\s+/:/g for @t使用这样一个事实:在for循环中,主题变量$_在这里是迭代元素的别名;更改它会更改元素(除非它们是只读的字符串文字)。所以s///改变 的元素@t

    \n

    一般来说,这不是一个好的做法,但在这种形式中,我认为它有点像一种习语,因为它非常独特,一旦你知道它的作用,它就非常清晰和明显。如果不是,请重写得更好一些。

    \n
  • \n
\n
\n

\xe2\x80\xa0例如

\n
my @t = split / (?<= \\]|=\\w) ,\\s* /x, $inside_curlies;\n
Run Code Online (Sandbox Code Playgroud)\n

分割是在逗号上进行的,逗号前面是]=\\w。它在给定的字符串上产生正确的结果,但我们不能说,=\\w+因为后视 (?<= ...)不能采用具有任意长度匹配的模式(什么\\w+)。

\n

B=x 所以如果它可以是或 , 我们就不能像这样匹配B=x1。在较新的 Perls 中,lookbehind 适用于最多 255 个字符的可变长度匹配。所以我们可以(?<= \\]|=\\w{1,254)),如果我们知道接下来的内容=不会更长。但这变得很尴尬。

\n

其他数据修改很容易想象,但也不容易适应。

\n

这被归为脚注,因为我认为这不是一个好的解决方案。

\n