3

以前はデータベース内のテーブルでしたが、現在は逆アセンブルされているいくつかのテキスト ファイルがあります。再組み立てを試みていますが、使用可能な形になったら簡単です。最初のファイル「keys.text」はラベルのリストであり、形式が一貫していません。お気に入り:

Sa 1 #
Sa 2
U 328 #*

常に文字、[スペース]、数字、[スペース]、および場合によっては記号です。これらのキーに一致するテキスト ファイルは同じで、その後にスペースで区切られた、または区切られたテキスト行が続きます。

Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...

以下のコードで私がやろうとしているのは、「keys.text」のキーを .txt ファイルの同じキーと一致させ、キーとテキストの間にタブを入れることです。私は非常に基本的なものを見落としていると確信していますが、得られた結果はソースの .txt ファイルと同じように見えます。

リードや支援をよろしくお願いします!

#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;
open(IN1, "keys.text");

my $key;

# Read each line one at a time
while ($key = <IN1>) {

# For each txt file in the current directory
foreach my $file (<*.txt>) {
  open(IN, $file) or die("Cannot open TXT file for reading: $!");
  open(OUT, ">temp.txt") or die("Cannot open output file: $!");

  # Add temp modified file into directory 
  my $newFilename = "modified\/keyed_" . $file;
  my $line;

  # Read each line one at a time
  while ($line = <IN>) {

     $line =~ s/"\$key"/"\$key" . "\/t"/;
     print(OUT "$line");

  }
  rename("temp.txt", "$newFilename");
 }   
}

編集:明確にするために、結果はキーからのシンボルも保持する必要があります。したがって、それらは次のようになります。

Sa 1 #      Random line of text follows.
Sa 2        This text is just as random.
U 328 #*    Continuing text...
4

6 に答える 6

1

正規表現は、私にはかなり奇妙に引用されているようです。しません

$line =~ s/$key/$key\t/;

よく働く?

また、IIRC は<IN1>$key の末尾に改行を残します。 chomp $keyそれを取り除くために。

printまた、特にファイル ハンドルに書き込んでいる場合は、引数を括弧で囲んではいけません。それが正しいかどうかにかかわらず、間違っているように見え、実際の問題から人々の注意をそらします。

于 2010-07-21T00:28:28.417 に答える
0

楽しい答え:

$line =~ s/(?<=$key)/\t/;

XXXXのゼロ幅のポジティブルックビハインドはどこ(?<=XXXX)にありますか。つまり、置換される一致の一部になることなく、XXXXの直後に一致します。

と:

$line =~ s/$key/$key . "\t"/e;

最後の/eフラグはeval、前の後半にあることの1つを実行してs///から入力することを意味します。

重要な注意:これらのどちらもお勧めしません。プログラムをわかりにくくします。しかし、彼らは興味深いです。:-)

于 2010-07-21T02:34:38.947 に答える
0

問題を簡単にするのsplitではなく使用する。s///以下のコードでは、read_keysからキーを抽出keys.textし、ハッシュに記録します。

次に、コマンドラインで指定された、特別なPerl配列で使用可能なすべてのファイルについて、@ARGV各行を調べて、キーで始まっているかどうかを確認します。そうでない場合はそのままにしておきますが、それ以外の場合は、キーとテキストの間にTABを挿入します。

-iPerlの便利なオプションのおかげで、ファイルをインプレースで編集することに注意してください。

-i[拡張子]

コンストラクトによって処理されるファイル<>をインプレースで編集することを指定します。これを行うには、入力ファイルの名前を変更し、元の名前で出力ファイルを開き、その出力ファイルをprintステートメントのデフォルトとして選択します。拡張子が指定されている場合は、古いファイルの名前を変更してバックアップコピーを作成するために使用されます…</ p>

この行split " ", $_, 3は、現在の行を正確に3つのフィールドに分割します。これは、行のテキスト部分に存在する可能性が高い空白を保護するために必要です。

#! /usr/bin/perl -i.bak

use warnings;
use strict;

sub usage { "Usage: $0 text-file\n" }

sub read_keys {
  my $path = "keys.text";
  open my $fh, "<", $path
    or die "$0: open $path: $!";

  my %key;
  while (<$fh>) {
    my($text,$num) = split;
    ++$key{$text}{$num} if defined $text && defined $num;
  }

  wantarray ? %key : \%key;
}

die usage unless @ARGV;
my %key = read_keys;

while (<>) {
  my($text,$num,$line) = split " ", $_, 3;
  $_ = "$text $num\t$line" if defined $text &&
                              defined $num &&
                              $key{$text}{$num};
  print;
}

サンプル実行:

$ ./add-tab input

$ diff -u input.bak input
--- input.bak 2010-07-20 20:47:38.688916978 -0500
+++入力2010-07-2021:00:21.119531937 -0500
@@ -1,3 +1,3 @@
-Sa 1#テキストのランダムな行が続きます。
-Sa2このテキストも同様にランダムです。
-U 328#*続きのテキスト...
+ Sa 1#テキストのランダムな行が続きます。
+Sa2このテキストも同様にランダムです。
+ U 328#*続きのテキスト...
于 2010-07-21T02:01:34.710 に答える
0

Perl が必須でない場合は、この awk ワンライナーを使用できます

$ cat keys.txt
Sa 1 #
Sa 2
U 328 #*

$ cat mytext.txt
Sa 1 # Random line of text follows.
Sa 2 This text is just as random.
U 328 #* Continuing text...

$ awk 'FNR==NR{ k[$1 SEP $2];next }($1 SEP $2 in k) {$2=$2"\t"}1 ' keys.txt mytext.txt
Sa 1     # Random line of text follows.
Sa 2     This text is just as random.
U 328    #* Continuing text...
于 2010-07-21T00:30:32.470 に答える
0

各ファイルの 2 つの別々のスラープを行うのはどうですか。最初のファイルでは、キーを開き、予備ハッシュを作成します。2 番目のファイルについては、テキストをハッシュに追加するだけです。

use strict;
use warnings;

my $keys_file = "path to keys.txt";
my $content_file = "path to content.txt";
my $output_file = "path to output.txt";

my %hash = ();

my $keys_regex = '^([a-zA-Z]+)\s*\(d+)\s*([^\da-zA-Z\s]+)';

open my $fh, '<', $keys_file or die "could not open $key_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /$keys_regex/){
        my $key = $1;
        my $number = $2;
        my $symbol = $3;
        $hash{$key}{'number'} = $number;
        $hash{$key}{'symbol'} = $symbol;
    }
}
close $fh;

open my $fh, '<', $content_file or die "could not open $content_file";
while(<$fh>){
    my $line = $_;
    if ($line =~ /^([a-zA-Z]+)/){
        my $key = $1;
// strip content_file line from keys/number/symbols to leave text
        line =~ s/^$key//;
        line =~ s/\s*$hash{$key}{'number'}//;
        line =~ s/\s*$hash{$key}{'symbol'}//;
        $line =~ s/^\s+//g;
        $hash{$key}{'text'} = $line;
    }
}
close $fh;

open my $fh, '>', $output_file or die "could not open $output_file";
for my $key (keys %hash){
    print $fh $key . " " . $hash{$key}{'number'} . " " . $hash{$key}{'symbol'} . "\t" . $hash{$key}{'text'} . "\n";
}
close $fh;

私はまだそれをテストする機会がなく、解決策はすべての正規表現で少しハッキリしているように見えますが、試してみることができる何か他のアイデアを与えるかもしれません.

于 2010-07-21T13:09:58.150 に答える
0

これはmap、Perl の関数に最適な場所のようです! テキスト ファイル全体を配列に読み込み、配列全体に map 関数を適用します。他にやりたいことは、このquotemeta関数を使用して、キー内の可能な正規表現をすべてエスケープすることです。

使用するmapと非常に効率的です。また、ループ内でキー ファイルを開いたり閉じたりする必要がないように、キーを配列に読み込みます。これは O^2 アルゴリズムですが、キーがそれほど大きくなければ、それほど悪くはありません。

#! /usr/bin/env perl

use strict;
use vars;
use warnings;

open (KEYS, "keys.text")
    or die "Cannot open 'keys.text' for reading\n";
my @keys = <KEYS>;
close (KEYS);

foreach my $file (glob("*.txt")) {
    open (TEXT, "$file")
        or die "Cannot open '$file' for reading\n";
    my @textArray = <TEXT>;
    close (TEXT);

    foreach my $line (@keys) {
        chomp $line;
        map($_ =~ s/^$line/$line\t/, @textArray);
    }
    open (NEW_TEXT, ">$file.new") or
        die qq(Can't open file "$file" for writing\n);

    print TEXT join("\n", @textArray) . "\n";
close (TEXT);
}
于 2010-07-25T16:33:23.983 に答える