web-dev-qa-db-ja.com

テキストファイルを複数のテキストファイルに分割する方法

以下を含むentry.txtというテキストファイルがあります。

[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631
[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631
[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631

entry1.txtentry2.txtentry3.txtの3つのテキストファイルに分割したいと思います。内容は以下の通りです。

entry1.txt

[ entry1 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3633 3634 3636 3690 3691 3693 3766
3767 3769 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5628 5629 5631

entry2.txt

[ entry2 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4526
4527 4529 4583 4584 4586 4773 4774 4776 5153 5154
5156 5628 5629 5631

entry3.txt

[ entry3 ]
1239 1240 1242 1391 1392 1394 1486 1487 1489 1600
1601 1603 1657 1658 1660 2075 2076 2078 2322 2323
2325 2740 2741 2743 3082 3083 3085 3291 3292 3294
3481 3482 3484 3690 3691 3693 3766 3767 3769 4241
4242 4244 4526 4527 4529 4583 4584 4586 4773 4774
4776 5153 5154 5156 5495 5496 5498 5628 5629 5631

つまり、[文字は、新しいファイルを開始する必要があることを示します。

テキストファイルの自動分割を実現する方法はありますか?私の最終的な実際の入力entry.txtには、実際には200,001のエントリが含まれています。

WindowsまたはLinuxのいずれかでテキスト分割を行うのは素晴らしいことです。 Macマシンにアクセスできません。ありがとう!

4
Andrew

そして、これが素敵でシンプルなgawkワンライナーです:

$ gawk '{if(match($0, /^\[ (.+?) \]/, k)){name=k[1]}} {print >name".txt" }' entry.txt

これは、各エントリヘッダーが[ blahblah blah blah ]のように見える限り、各エントリの行数に関係なく、anyファイルサイズで機能します。開始[の直後と終了]の直前のスペースに注意してください。


説明:

awkおよびgawkは、入力ファイルを1行ずつ読み取ります。各行が読み取られると、その内容は$0変数に保存されます。ここでは、awkに角括弧内のすべてに一致し、その一致を配列kに保存するように指示しています。

したがって、その正規表現が一致するたびに、つまりファイル内のすべてのヘッダーについて、k [1]は行の一致した領域を持ちます。つまり、「entry1」、「entry2」、「entry3」、「entryN」です。 name=k[1]は、k [1](一致)の値を新しい変数nameに保存するだけです。

最後に、各行を<whatever value k currently has>.txtというファイルに出力します。つまり、entry1.txt、entry2.txt ... entryN.txtです。

この方法は、大きなファイルの場合、Perlよりもはるかに高速になります。

Windowsシェルを使用したことがないため、これを保証することはできませんが、それよりもfar高速になることは間違いありません。 Gawk/awkは高速です。

3
terdon

Windowsソリューションの場合は、次のPowerShellスクリプトを試してください。

$Path = "D:\Scripts\PS\test"
$InputFile = (Join-Path $Path "log.txt")
$Reader = New-Object System.IO.StreamReader($InputFile)

While (($Line = $Reader.ReadLine()) -ne $null) {
    If ($Line -match "\[ (.+?) \]") {
        $OutputFile = $matches[1] + ".txt"
    }

    Add-Content (Join-Path $Path $OutputFile) $Line
}

それに応じて、$Path変数と$InputFile変数を編集します。いくつかの小さな変更を加えることで、その情報をコマンドラインパラメーターとして受け入れることも、関数に変換することもできます。

4
Indrek

さらに別のawkソリューション:

BEGIN { 
  RS="\\[ entry[0-9]+ \\]\n"  # Record separator
  ORS=""                      # Reduce whitespace on output
}
NR == 1 { f=RT }              # Entries are of-by-one relative to matched RS
NR  > 1 {
  split(f, a, " ")            # Assuming entries do not have spaces 
  print f  > a[2] ".txt"      # a[2] now holds the bare entry name
  print   >> a[2] ".txt"
  f = RT                      # Remember next entry name
}
3
Thor

既存のコマンドを使用する方が簡単ではありませんか?すべてが新しいプログラムを必要とするわけではありません。

csplit/\ [/ファイル

2
mpez0

次のPerlスクリプトがその役割を果たします。

#!/ usr/bin/Perl 
 
 while(<STDIN>){
 if($ _ = 〜m/^\[(。+? )\] /){
 $ f = $ 1; 
 Tell(FH)!= -1; 
 open FH、 ">"、 "$ f.txtの場合はFHを閉じる"またはdie"ファイル$ fを開けませんでした:$!\ n "; 
} 
 print FH $ _; 
} 
 close FH; 

次のようなスクリプトを実行します。

script.pl < entry.txt

スクリプトは、含まれるエントリセクションの数や、エントリセクションのヘッダーのみが[ some text ]のようになっている限り、セクションの長さに関係なく機能します。


Perl -e 'while(<STDIN>){if($_=~/^\[ (.+?) \]/){close FH if tell FH!=-1;open FH,">","$1.txt"or die"$1.txt: $!";}print FH $_;}close FH;' < entry.txt
2
speakr