題 如何將文本文件拆分為多個文本文件


我有一個名為的文本文件 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。其內容如下。

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

換句話說, [ character表示應該開始一個新文件。

有什麼辦法可以完成自動文本文件拆分嗎?我最終的實際輸入 entry.txt 實際上包含200,001個條目。

在Windows或Linux中進行文本拆分會很棒。我無法訪問Mac機器。謝謝!


4
2017-08-25 22:00


起源


所有條目都有7行? - hamed
@hamed哎呀,我忘了提到,不幸的是,參賽作品並不都有7行。 - Andrew
檢查此應用: softpedia.com/get/System/File-Management/... - ray pixar


答案:


這是一個很好的,簡單的gawk單線程:

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

這將有用 任何 文件大小,與每個條目中的行數無關,只要每個條目標題看起來像 [ blahblah blah blah ]。注意開口後的空間 [ 就在結束之前 ]


說明:

awk 和 gawk 逐行讀取輸入文件。讀取每一行時,其內容將保存在 $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 shell,但我願意打賭它會  也快於那個。 Gawk / awk很快。


3
2017-08-26 01:23



這適用於gawk但不適用於awk(至少是默認Debian系統上的awk)。 awk的匹配函數只允許兩個參數,所以你的例子給出了awk的語法錯誤。 - speakr


對於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
2017-08-25 22:57





完後還有 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
2017-08-26 02:23





以下perl腳本完成了這項工作:

#!的/ usr / bin中/ perl的

while(<STDIN>){
    if($ _ = ~m / ^ \ [(。+?)\] /){
        $ f = $ 1;
        告訴FH如果告訴(FH)!= -1;
        打開FH,“>”,“$ f.txt”或“無法打開文件$ f:$!\ n”;
    }
    打印FH $ _;
}
關閉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
2017-08-25 22:42



你不需要 cat,你可以跑 script.pl test.txt。 - terdon
@terdon不,如果你使用 STDIN 您不能將文本文件作為參數傳遞。然而, script.pl < test.txt 比使用更好 cat  - 我相應地更新了我的答案。 - speakr
你很對,抱歉。我太習慣了 while(<>) 它將輸入文件作為第一個參數。 - terdon


使用現有命令不簡單嗎?並非一切都需要一個新的計劃。

csplit / \ [/ file


2
2017-09-04 12:07



你是對的, csplit 是工作的正確工具。我不得不添加重複計數並交換參數以使其工作。以下命令行接近OP要求的內容: csplit -f entry -b '%d.txt' -z entry.txt '/^\[/' '{*}'。 - Thor
然而, csplit 僅當文件中的記錄名稱隨後時才會起作用 entryXX 模式,'因為它不支持設置變量前綴 - Suncatcher