用Perl标记逗号

问题描述 投票:2回答:2

请从this code解释这两行Perl。

# separate out "," except if within numbers (5,300)
# previous "global" application skips some:  A,B,C,D,E > A , B,C , D,E
# first application uses up B so rule can't see B,C
# two-step version here may create extra spaces but these are removed later
# will also space digit,letter or letter,digit forms (redundant with next section)
$text =~ s/([^\p{IsN}])[,]/$1 , /g;
$text =~ s/[,]([^\p{IsN}])/ , $1/g;
regex perl
2个回答
4
投票

您的代码会进行两次替换。 s///是一个替换,/g标志告诉它在全球范围内进行,基本上是替换所有。

两行都在正则表达式中使用\p{} unicode property character groups。使用IsN,它会检查字符是否为数字。

/            
 (           # capture group
  [          # character group
   ^         # not the following characters
   \p{IsN}   # all characters that are a number
  ]
 )
 [,]         # followed by a comma
/

它取代了捕获的不是数字,空格,逗号和空格。

第二行也是如此,但首先是逗号。

您可以使用相同的功能将此代码重写为更短,更简洁。 \P{}是所有没有这个属性的字符,这消除了对[]的需要。这可以进一步缩短到\PN

$text =~ s/(\PN),/$1 , /g;
$text =~ s/,(\PN)/ , $1/g;

2
投票
  1. ␠,␠替换前面没有“Number”Unicode General Category的字符的所有逗号。
  2. ␠,␠替换所有逗号,后跟一个没有“Number”Unicode General Category的字符。

嗯,不太好。因为逗号本身是非数字字符,所以上面没有准确描述当一行中有两个逗号时会发生什么。

但是,由于A,B成为A␠␠,␠␠B,它不能很好地运作,因此不值得深入细节。

标记生成器:

my @tokens;
for ($text) {
   if (/\G ( (?: [^,\d]++ | \d(?:,\d++)*+ )++ ) /xgc) {
      push @tokens, [ TEXT => $1 ];
      redo;
   }

   if (/\G , /xgc) {
      push @tokens, [ 'COMMA' ];
      redo;
   }

   if (/\G \z /xgc) {
      push @tokens, [ 'EOF' ];
      last;
   }

   die("Internal error\n");
}
© www.soinside.com 2019 - 2024. All rights reserved.