3

次のコンマ区切り値の行には、いくつかの連続した空のフィールドが含まれています。

$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

私が欲しかったものではありません。この問題は、3つ以上の連続したコンマが発生した場合に発生します。正規表現は一度に2つのコンマを飲み込むため、文字列を再スキャンするときは2番目ではなく3番目のコンマから始まります。

これは先読みアサーションと先読みアサーションに関係している可能性があると思ったので、次の正規表現を試してみました。

$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

それもうまくいきませんでした。カンマペアを1つシフトしただけです。

この文字列を同じ正規表現で2回洗浄するとうまくいくことはわかっていますが、それは大雑把に思えます。確かに、仕事をするために単一の正規表現置換を取得する方法がなければなりません。助言がありますか?

最終的な文字列は次のようになります。

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
4

5 に答える 5

3

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不要になります。

于 2009-10-29T19:54:05.977 に答える
2

後読みの例であなたが何をしようとしていたのかよくわかりませんでしたが、そこで優先順位エラーが発生している可能性があります。後読みの後のすべてをで囲む必要がある(?: ... )ため、後読みを|回避することはできません。 。

最初から始めようとしていることは非常に単純に聞こえます。別のコンマまたは改行が続く場合は、コンマの後に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"
于 2009-10-29T20:12:40.910 に答える
2

あなたは検索することができます

(?<=,)(?=,|$)

それをN/Aに置き換えます。

この正規表現は、2つのコンマの間、またはコンマと行末の間の(空の)スペースに一致します。

于 2009-10-29T20:13:01.847 に答える
1

迅速で汚いハックバージョン:

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;

最速のコードではありませんが、最短のコードです。最大で2回ループする必要があります。

于 2009-10-29T20:10:57.893 に答える
1

正規表現ではありませんが、それほど複雑でもありません。

$string = join ",", map{$_ eq "" ? "N/A" : $_} split (/,/, $string,-1);

文字列の最後に空のフィールドを含めるよう,-1に強制するには、最後にが必要です。split

于 2009-10-29T20:16:46.510 に答える