Bir metin dosyasını birden fazla metin dosyasına bölme


4

entry.txtAşağıdakileri içeren bir metin dosyası var :

[ 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

Üç metin dosyaları bölmek istiyorum: entry1.txt, entry2.txt, entry3.txt. İçindekiler aşağıdaki gibidir.

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

Başka bir deyişle, [karakter yeni bir dosyanın başlaması gerektiğini belirtir.

Otomatik metin dosyası bölme işlemini başarabilmemin bir yolu var mı? Sonunda, gerçek entry.txtgirişim aslında 200.000 giriş içeriyor.

Metni Windows veya Linux'ta bölmek çok iyi olurdu. Bir Mac makinesine erişimim yok. Teşekkürler!


tüm kayıtlarda 7 satır var mı?
hamed

@hamed Hata, ne yazık ki, girişlerin hepsinde 7 satır olmadığını belirtmeyi unuttum.
Andrew

Yanıtlar:


3

Ve işte güzel, basit bir tek kişilik gömlek:

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

Bu, her giriş başlığında göründüğü sürece, her girişdeki satır sayısından bağımsız olarak herhangi bir dosya boyutu için çalışacaktır [ blahblah blah blah ]. Açılıştan hemen sonra [ve kapanmadan hemen önce boşluğa dikkat edin ].


AÇIKLAMA:

awkve gawkbir giriş dosyasını satır satır okuyun. Her satır okunurken, içerikleri $0değişkene kaydedilir . Burada, köşeli parantez içindeki herhangi birşeyle eşleşmesini ve eşleşmesini diziye kaydetmesini söylüyoruz k.

Bu nedenle, düzenli ifadenin her eşleşmesinde, yani dosyanızdaki her başlık için, k [1] satırın eşleşen bölgesine sahip olacaktır. Yani, "entry1", "entry2" veya "entry3" veya "entryN". name=k[1]sadece k [1] (eşleşme) değerini yeni bir değişkene kaydeder name.

Son olarak, her satırı <whatever value k currently has>.txt, yani entry1.txt, entry2.txt ... entryN.txt adlı bir dosyaya yazdırırız.

Bu yöntem daha büyük dosyalar için perl'den çok daha hızlı olacaktır .

Ben pencere kabuk hiç kullanılmamış gibi bunun için kefil olamaz, ama ben öyle olacak bahse girerim kadar da bundan daha hızlı. Gawk / awk HIZLI.


Bu gawk ile çalışır ancak awk ile çalışmaz (en azından varsayılan Debian sistemindeki awk). awk eşleştirme işlevi yalnızca iki parametreye izin verir, bu nedenle örneğiniz awk ile bir sözdizimi hatası verir.
saat

4

Windows çözümü için bu PowerShell betiğini deneyin:

$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
}

$PathVe $InputFiledeğişkenlerini buna göre düzenleyin . Bazı küçük değişikliklerde, bu bilgileri komut satırı parametreleri olarak da kabul edebilir veya bir işleve dönüştürebilirsiniz.


3

Yine başka bir awkçözüm:

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
}

2

Aşağıdaki perl betiği işi yapar:

#! / Usr / bin / perl

süre (<STDIN>) {
    eğer ($ _ = ~ m / ^ \ [(. +?) \] /) {
        $ f = 1 $;
        anlatırsanız FH'yi kapatın (FH)! = -1;
        FH’yi açın, ">", "$ f.txt" ya da die "$ f: $! \ n" dosyasını açamadı;
    }
    FH $ _ yazdırın;
}
FH'yi kapatın;

Komut dosyasını şu şekilde çalıştırın:

script.pl < entry.txt

Komut, kaç tane giriş bölümü dahil edilse ve bölümlerin yalnızca giriş bölümü başlıkları ne kadar uzun olursa olsun çalışır [ some text ].


Okunamayan kodu tercih ediyorsanız veya bir komut dosyasını bir yerde saklamak istemiyorsanız, şu tek komutu kullanabilirsiniz:

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

İhtiyacın yok cat, sadece koşabilirsin script.pl test.txt.
terdon

@ terdon Hayır, kullanırsanız STDINmetin dosyasını parametre olarak iletemezsiniz . Ancak, script.pl < test.txtkullanmaktan daha iyidir cat- Cevabımı buna göre güncelledik.
saat

Çok haklısın üzgünüm. Ben de while(<>)girdi dosyasını ilk argüman olarak kabul etmeye alışkınım .
terdon

2

Mevcut komutları kullanmak daha kolay değil mi? Her şey yeni bir program gerektirmez.

csplit / \ [/ dosya


Haklısın, csplitiş için doğru araçtır. Bir tekrar sayımı eklemek ve argümanları değiştirebilmek için takas etmek zorunda kaldım. Aşağıdaki komut satırı OP için ne sordu yakın gelir: csplit -f entry -b '%d.txt' -z entry.txt '/^\[/' '{*}'.
Thor

Ancak, csplityalnızca dosyadaki kayıt adı entryXXkalıbı izlerse çalışacaktır , 'değişken önekleri ayarlamayı desteklemediği için
Suncatcher
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.