0

次のような長い行を含むファイルがあります。

XEP.101     :1804 000000:I:XEPInfoFormat:Status=ok:TID=00000000516F6161-000874C3-00003E19-62F2B0C6:CallType=gprs:CallStart=20130415210553:CallDuration=4334:ServedParty=724044024363999:ServedLocation=724:OtherParty=TIM:OtherLocation=tim.br:ServedZone=ZO00001:OtherZone=ZP32363:TariffZone=ZN1261:CUST_ID=58922505:CO_ID=58891164:account=8327813:MSISDN=554599836655:theoretical_cost_value=33.323525:BA_Line_Main_value=NA:Tariff=TM_PL5PR:FU_Packs_used=FU_PLWI2:SNCODE_FU=1350_1250_1_BA_FU_PLWI2_Byt_Internet2:MCs_used=NO:bcd=20100319,bcp=P1M:InputFilename=201304172345.000020:EipFilename=/gold/rte/data/RatedEvents/EIP/10/101201304172345.000020:RtxFilename=/gold/rte/data/RatedEvents/RTX/01/OPSCGOLD_20130418000000_1011917.xml:BadrateFilename=/gold/rte/data/BadRate/bad_rate_xep10.201304172345.000020.tmp:FILE=/gold/rte/data/IncomingCDRs/ASN1/010/GPRS99+GPRS99-46299-1304172357-SA.TTF;TICKET=660

したがって、Perl で次の行に一致させるために、この条件があります。

if ( $line =~ m/XEP.[0-9].*:(\d{4}) (\d{2})(\d{2})(\d{2}).*XEPInfoFormat:Status=(\w*):TID=(\S*):CallType=(\w*):CallStart=(\d*):CallDuration=(\d*):ServedParty=(\d*):ServedLocation=(\d*):OtherParty=(\w*):OtherLocation=(\w*):ServedZone=(\w*):OtherZone=(\w*):TariffZone=(\w*):CUST_ID=(\d*):CO_ID=(\d*):account=(\d*):MSISDN=(\d*):theoretical_cost_value=(\d*)\.(\d*):BA_Line_Main_value=(\w*):Tariff=(\w*):FU_Packs_used=(\w*):SNCODE_FU=(\w*):MCs_used=(\w*):bcd=(\d*),bcp=(\w*):InputFilename=(\d*)\.(\d*):EipFilename=\/\w*\/\w*\/\w*\/\w*\/\w*\/(\d*)\/(\d*)\.(\d*).*FILE=\/\w*\/\w*\/\w*\/\w*\/\w*\/(\d*)\/(\w*)\+(\w*)-(\d*)-(\d*)-(\w*).(\w*);TICKET=(\d*)/ ) {

だから私にとっては大丈夫です。これは一致しており、結果をもたらしています。ただし、たとえば、この行全体を一致させ、一致のフィールドをスクリプトのオプションとして指定したい場合など、より柔軟にしたいと考えています (例: TID= の前に含まれる)。私がやろうとしているのは:

use Getopt::Std;
getopts("Ch:t:",\%opts);

if ( $opts{t} ) {
    $TIDS = $opts{t};
} else {
    $TIDS = '/S*';
}

だから、私はこのようにしようとしています.getopts -tを使用して、変数$ TIDSで一致を置き換えます

if ( $line =~ m/XEP.[0-9].*:(\d{4}) (\d{2})(\d{2})(\d{2}).*XEPInfoFormat:Status=(\w*):TID=(${TIDS})

したがって、-t オプションでパラメーターを指定すると、次のようになります。

perl-script.pl -t 888894343

正規表現全体で次のように一致することを望みます:

if ( $line =~ m/XEP.[0-9].*:(\d{4}) (\d{2})(\d{2})(\d{2}).*XEPInfoFormat:Status=(\w*):TID=(888894343)

ただし、これを指定しない場合は、次のように一致することを望みます。

if ( $line =~ m/XEP.[0-9].*:(\d{4}) (\d{2})(\d{2})(\d{2}).*XEPInfoFormat:Status=(\w*):TID=(/S*)

すべての行を (/S*) で単純に一致させてから、以下のような単純な if 条件を入れることができることはわかっていますが、この方法では、例として挙げたような行がたくさんあるため、パフォーマンスが低下します。柔軟に対応したい

print "$line\n" if $6 eq $TIDS;

誰にもアイデアはありますか?quotemeta を使用して、単純な引用符で囲み、正規表現を二重引用符で囲みましたが、機能しませんでした。

4

3 に答える 3

0

コードが機能しない主な理由は、0 個以上の空白文字であるではなく'/S*'、スラッシュの後に 0 個以上の文字が続く を使用していることです。S'\S*'

ただし、正規表現を使用するよりも、 を使用して各レコードをフィールドに分割する方がよいと思いますsplit /:/。さらに、最初の 4 つ以降のフィールドはすべて forname=valueであるため、簡単にアクセスできるように便利にハッシュに入れることができます。あとはチェックするだけですif ($ch{t} eq $params{TID}) { ... }

このコードは示しています。構築されたハッシュData::Dumpの内容を表示するために使用しました。%params最初の 4 つのフィールドの情報が重要かどうかは不明@paramsですが、必要な場合に備えて抽出しました。

use strict;
use warnings;

use Data::Dump;

my %opts = (t => 888894343);

while (my $line = <DATA>) {
  chomp $line;
  my %params = $line =~ /([^:=]+)=([^:=]+)/g;
  ddx \%params;
  #next if $opts{t} and $params{TID} ne $opts{t};
  my @params = (split /:/, $line, 5)[0..3];
  ddx \@params;
  #print $line;
}

__DATA__
XEP.101     :1804 000000:I:XEPInfoFormat:Status=ok:TID=00000000516F6161-000874C3-00003E19-62F2B0C6:CallType=gprs:CallStart=20130415210553:CallDuration=4334:ServedParty=724044024363999:ServedLocation=724:OtherParty=TIM:OtherLocation=tim.br:ServedZone=ZO00001:OtherZone=ZP32363:TariffZone=ZN1261:CUST_ID=58922505:CO_ID=58891164:account=8327813:MSISDN=554599836655:theoretical_cost_value=33.323525:BA_Line_Main_value=NA:Tariff=TM_PL5PR:FU_Packs_used=FU_PLWI2:SNCODE_FU=1350_1250_1_BA_FU_PLWI2_Byt_Internet2:MCs_used=NO:bcd=20100319,bcp=P1M:InputFilename=201304172345.000020:EipFilename=/gold/rte/data/RatedEvents/EIP/10/101201304172345.000020:RtxFilename=/gold/rte/data/RatedEvents/RTX/01/OPSCGOLD_20130418000000_1011917.xml:BadrateFilename=/gold/rte/data/BadRate/bad_rate_xep10.201304172345.000020.tmp:FILE=/gold/rte/data/IncomingCDRs/ASN1/010/GPRS99+GPRS99-46299-1304172357-SA.TTF;TICKET=660

出力

# para.pl:11: {
#   account                => 8327813,
#   BA_Line_Main_value     => "NA",
#   BadrateFilename        => "/gold/rte/data/BadRate/bad_rate_xep10.201304172345.000020.tmp",
#   bcd                    => "20100319,bcp",
#   CallDuration           => 4334,
#   CallStart              => 20130415210553,
#   CallType               => "gprs",
#   CO_ID                  => 58891164,
#   CUST_ID                => 58922505,
#   EipFilename            => "/gold/rte/data/RatedEvents/EIP/10/101201304172345.000020",
#   FILE                   => "/gold/rte/data/IncomingCDRs/ASN1/010/GPRS99+GPRS99-46299-1304172357-SA.TTF;TICKET",
#   FU_Packs_used          => "FU_PLWI2",
#   InputFilename          => "201304172345.000020",
#   MCs_used               => "NO",
#   MSISDN                 => 554599836655,
#   OtherLocation          => "tim.br",
#   OtherParty             => "TIM",
#   OtherZone              => "ZP32363",
#   RtxFilename            => "/gold/rte/data/RatedEvents/RTX/01/OPSCGOLD_20130418000000_1011917.xml",
#   ServedLocation         => 724,
#   ServedParty            => 724044024363999,
#   ServedZone             => "ZO00001",
#   SNCODE_FU              => "1350_1250_1_BA_FU_PLWI2_Byt_Internet2",
#   Status                 => "ok",
#   Tariff                 => "TM_PL5PR",
#   TariffZone             => "ZN1261",
#   theoretical_cost_value => 33.323525,
#   TID                    => "00000000516F6161-000874C3-00003E19-62F2B0C6",
# }
# para.pl:14: ["    XEP.101     ", "1804 000000", "I", "XEPInfoFormat"]
于 2013-04-20T18:41:02.573 に答える
0

別の提案。の値をチェックしTIDて一度に行を解析する必要はありません: 最初にレコードの非常に高速なチェックを行い、次に (ハッシュ手法または選択した正規表現を使用して) 解析することができます。興味。

while (<>) {
  next if $opts{t} and $line !~ /:TID=$opts{t}:/;
  # Parse and process record
}
于 2013-04-20T19:16:01.883 に答える
0

コマンドライン引数などの変数で quotemeta を使用しようとしている場合は、次のようにする必要があります。

$foo = quotemeta($ARGV[0]);
于 2013-04-20T18:23:50.747 に答える