![](/img/trans.png)
[英]How can I use unicode characters in perl regex substitution command?
[英]How do I use Perl to intersperse characters between consecutive matches with a regex substitution?
以下逗号分隔值行包含几个连续的空字段:
$rawData =
"2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,Clear\n
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,,,\n"
我想用'N / A'值替换这些空字段,这就是为什么我决定通过正则表达式替换它。
我首先尝试了这个:
$rawdata =~ s/,([,\n])/,N\/A/g; # RELABEL UNAVAILABLE DATA AS 'N/A'
哪个回来了
2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,N/A,Clear\n
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,N/A,,N/A,\n
不是我想要的。 出现两个以上连续逗号时会出现此问题。 正则表达式一次吞噬两个逗号,所以它从第三个逗号开始,而不是第二个逗号重新扫描字符串时。
我认为这可能与lookahead vs. lookback断言有关,所以我尝试了以下正则表达式:
$rawdata =~ s/(?<=,)([,\n])|,([,\n])$/,N\/A$1/g; # RELABEL UNAVAILABLE DATA AS 'N/A'
结果导致:
2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,N/A,Clear\n
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,N/A,,N/A,,N/A,,N/A\n
那也行不通。 它只是将逗号配对移动了一个。
我知道通过相同的正则表达式两次清洗这个字符串会做到这一点,但这看起来很粗糙。 当然,必须有一种方法可以让一个正则表达式替换来完成这项工作。 有什么建议么?
最终字符串应如下所示:
2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,N/A,N/A,Clear\n
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,N/A,,N/A,N/A,N/A,N/A,N/A\n
编辑:请注意,您可以打开数据字符串的文件句柄,让readline
处理行结尾:
#!/usr/bin/perl
use strict; use warnings;
use autodie;
my $str = <<EO_DATA;
2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,Clear
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,,,
EO_DATA
open my $str_h, '<', \$str;
while(my $row = <$str_h>) {
chomp $row;
print join(',',
map { length $_ ? $_ : 'N/A'} split /,/, $row, -1
), "\n";
}
输出:
E:\Home> t.pl 2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,N/A,Clear 2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,N/A,N/A,N/A,N/A
您还可以使用:
pos $str -= 1 while $str =~ s{,(,|\n)}{,N/A$1}g;
说明:当s///
找到一个,,
并用,N/A,
替换它时,N/A,
它已经移动到最后一个逗号后面的字符。 所以,如果你只使用它,它会遗漏一些连续的逗号
$str =~ s{,(,|\n)}{,N/A$1}g;
因此,在每次成功替换后,我使用循环将pos $str
移回一个字符。
现在,正如@ysth所示 :
$str =~ s!,(?=[,\n])!,N/A!g;
将使while
不必要的。
我无法弄清楚你在后面的示例中想要做什么,但我怀疑你在那里遇到了一个优先级错误,并且在lookbehind之后的所有内容都应该包含在(?: ... )
所以|
不会避免做后卫。
从头开始,您尝试做的事情听起来很简单:如果后面跟着另一个逗号或换行符,请在逗号后面放置N / A:
s!,(?=[,\n])!,N/A!g;
例:
my $rawData = "2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,Clear\n2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,,,\n";
use Data::Dumper;
$Data::Dumper::Useqq = $Data::Dumper::Terse = 1;
print Dumper($rawData);
$rawData =~ s!,(?=[,\n])!,N/A!g;
print Dumper($rawData);
输出:
"2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,Clear\n2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,,,\n"
"2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,N/A,Clear\n2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,N/A,N/A,N/A,N/A\n"
你可以搜索
(?<=,)(?=,|$)
并用N / A代替。
此正则表达式匹配两个逗号之间或逗号和行尾之间的(空)空格。
快速而肮脏的黑客版本:
my $rawData = "2008-02-06,8:00 AM,14.0,6.0,59,1027,-9999.0,West,6.9,-,N/A,,Clear
2008-02-06,9:00 AM,16,6,40,1028,12,WNW,10.4,,,,\n";
while ($rawData =~ s/,,/,N\/A,/g) {};
print $rawData;
不是最快的代码,但最短的。 它应该最多循环两次。
不是正则表达式,但也不是太复杂:
$string = join ",", map{$_ eq "" ? "N/A" : $_} split (/,/, $string,-1);
最后需要,-1
,强制split
以包括字符串末尾的任何空字段。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.