下面的线条的逗号分隔值包含几个连续的空领域:

$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
有帮助吗?

解决方案

我不能完全辨认出你试图在你的回顾后为例做,但我怀疑你是从优先级错误苦难存在,我们的回顾后之后一切都应该在(?: ... )被封闭,因此|没有按”吨避免做了回顾后发

一个逗号后,如果它是跟其他逗号或换行的地方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"

其他提示

编辑:注意,你可以打开一个文件句柄的数据串而让 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到包括在所述字符串的末尾任何空字段。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top