![](/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.