我怎么使用Perl散布字之间的连续比赛regex替代?
-
22-07-2019 - |
题
下面的线条的逗号分隔值包含几个连续的空领域:
$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"价值观,这就是为什么我决定做的,它通过regex替代。
我想这首先:
$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
不是我想要的。发生问题时超过连续两个逗号发生的。Regex狼吞虎咽起来的两个逗号在一段时间,所以它开始在第三个逗号,而不是第二,当它重新扫描。
我想这可能是一些做lookahead与回顾断言,所以,我尝试过的以下regex出:
$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
没有工作。这只是转移逗号分配通过一个。
我知道洗衣这串通过相同的regex两次将做到这一点,但这似乎是原油。当然,必须有一个方法得到一个单一的regex替代做的工作。任何建议?
最后串应该是这样的:
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
解决方案
我不能完全辨认出你试图在你的回顾后为例做,但我怀疑你是从优先级错误苦难存在,我们的回顾后之后一切都应该在(?: ... )
被封闭,因此|
没有按”吨避免做了回顾后发
从头开始,你正在尝试做听起来很简单
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"
其他提示
编辑:注意,你可以打开一个文件句柄的数据串而让 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,
它已经转移到字之后的最后的逗号。因此,它将错过一些连续逗号,如果仅使用
$str =~ s{,(,|\n)}{,N/A$1}g;
因此,我使用一个循环移动 pos $str
回通过一个字之后的每一个成功的替代。
现在,作为 @ysth显示:
$str =~ s!,(?=[,\n])!,N/A!g;
会做的 while
不必要的。
您可以搜索
(?<=,)(?=,|$)
和替换用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
到包括在所述字符串的末尾任何空字段。