Memisahkan file teks berdasarkan pada ekspresi reguler


16

Saya memiliki file teks yang ingin saya bagi menjadi 64 bagian yang tidak sama, menurut 64 heksagram Yi Jing. Karena bagian untuk setiap heksagram dimulai dengan beberapa digit, satu periode, dan dua baris baru, regex harus cukup mudah untuk ditulis.

Tetapi bagaimana saya benar-benar membagi file teks menjadi 64 file baru sesuai dengan regex ini? Sepertinya lebih dari tugas untuk perl. Tapi mungkin ada cara yang lebih jelas bahwa saya benar-benar hilang.

Jawaban:


23

Ini akan csplitkecuali bahwa regex harus menjadi satu baris. Itu juga membuat sedsulit; Saya akan menggunakan Perl atau Python.

Anda bisa melihat apakah

csplit foo.txt '/^[0-9][0-9]*\.$/' '{64}'

cukup baik untuk keperluan Anda. ( csplitmembutuhkan POSIX BRE, jadi tidak bisa menggunakan \datau +, antara lain.)


Terima kasih, @geekosaur. Itu bekerja dengan sempurna, meskipun saya harus mengubahnya ke {63}.
ixtmixilix

1
Jadi, '\.'tidak akan bekerja juga?
Vanuan

4

Saya pikir cara terbaik adalah awkdan gawk.

awk

awk -F "([.] )|( / )" '/^[0-9]{1,3}[.]/{x="F"$1"("$2").txt";}{print >x;}' I_Ching_Wilhelm_Translation.txt

-Fakan menentukan pemisah bidang untuk setiap baris. Ini adalah regex, di sini kami menggunakan beberapa pemisah: ". "dan " / ". Dengan demikian garis seperti 1. Ch'ien / The Creativeakan dibagi menjadi 3 bidang: 1 Ch'iendan The Creative. Nanti kita bisa merujuk ke kolom-kolom ini dengan $n. $0adalah seluruh baris.

Kami kemudian memberi tahu awk untuk mencocokkan garis dengan pola ^[0-9]{1,3}[.]Jika ada yang cocok, kami kemudian memberikan nilainya x. Nilai x akan digunakan sebagai nama file untuk printoperasi. Dalam contoh ini kita menggunakan "F"$1"("$2").txt"sehingga baris 1. Ch'ien / The Creativememberi nama fileF1(Ch'ien).txt

melongo

Di gawk, kita juga dapat mengakses grup yang ditangkap. Jadi kita bisa menyederhanakan perintah untuk:

gawk 'match($0, /^([0-9]{1,3})[.] (.*) \/ (.*)$/, ary){x="F"ary[1]"("ary[2]")";}{print >x;}' I_Ching_Wilhelm_Translation.txt

di sini kita menggunakan matchmenangkap grup dan memasukkannya ke dalam daftar variabel ary. $0adalah seluruh baris. ary[0]semuanya cocok. ary[1...n]masing-masing kelompok.

perl

Kita juga bisa melakukannya dengan perl:

perl -ne 'if(/^([0-9]{1,3})[.] (.*) \/ (.*)$/) {close F; open F, ">", sprintf("F$1($2).txt");} print F' I_Ching_Wilhelm_Translation.txt

Hasil:

> ls F*
F10(Lü).txt         F22(Pi).txt       F34(Ta Chuang).txt  F46(Shêng).txt     F58(Tui).txt
F11(T'ai).txt       F23(Po).txt       F35(Chin).txt       F47(K'un).txt      F59(Huan).txt
F12(P'i).txt        F24(Fu).txt       F36(Ming I).txt     F48(Ching).txt     F5(Hsü).txt
F13(T'ung Jên).txt  F25(Wu Wang).txt  F37(Chia Jên).txt   F49(Ko).txt        F60(Chieh).txt
F14(Ta Yu).txt      F26(Ta Ch'u).txt  F38(K'uei).txt      F4(Mêng).txt       F61(Chung Fu).txt
F15(Ch'ien).txt     F27(I).txt        F39(Chien).txt      F50(Ting).txt      F62(Hsiao Kuo).txt
F16(Yü).txt         F28(Ta Kuo).txt   F3(Chun).txt        F51(Chên).txt      F63(Chi Chi).txt
F17(Sui).txt        F29(K'an).txt     F40(Hsieh).txt      F52(Kên).txt       F64(Wei Chi).txt
F18(Ku).txt         F2(K'un).txt      F41(Sun).txt        F53(Chien).txt     F6(Sung).txt
F19(Lin).txt        F30(Li).txt       F42(I).txt          F54(Kuei Mei).txt  F7(Shih).txt
F1(Ch'ien).txt      F31(Hsien).txt    F43(Kuai).txt       F55(Fêng).txt      F8(Pi).txt
F20(Kuan).txt       F32(Hêng).txt     F44(Kou).txt        F56(Lü).txt        F9(Hsiao Ch'u).txt
F21(Shih Ho).txt    F33(TUN).txt      F45(Ts'ui).txt      F57(Sun).txt

cara mendapatkan file contoh:

curl http://www2.unipr.it/~deyoung/I_Ching_Wilhelm_Translation.html|html2text -o I_Ching_Wilhelm_Translation.plain
sed 's|^[[:blank:]]*||g' I_Ching_Wilhelm_Translation.plain > I_Ching_Wilhelm_Translation.txt

3

Dengan GNU coreutils, Anda dapat menggunakan csplituntuk memecah file menjadi potongan-potongan terbatas-regexp, seperti yang ditunjukkan oleh geekosaur .

Berikut ini adalah skrip awk portabel untuk memecah file menjadi beberapa bagian. Ini bekerja dengan

  • panggilan getlineuntuk berurusan dengan pemisah multiline (2-line);
  • mengatur variabel outfileke nama file yang akan dicetak, ketika header bagian ditemui.
BEGIN {outfile="header.txt"}
{
    while (/^[0-9]+\.$/) {
        prev = $0; getline;
        if ($0 == "") outfile = prev "txt";
        print prev >outfile
    }
    print >outfile
}

Ini bekerja pada prinsipnya , tetapi bagian-header dari data halaman web yang sebenarnya tidak seperti yang diwakili oleh regex (demikian juga dengan jawaban geekosaurus). Bagian depan nunber. diikuti oleh teks yang berisi garis miring /. Saya cukup yakin two newlines ixtmixilix yang disebutkan adalah 2 baris kosong yang mendahului pengidentifikasi angka dan akan lebih spesifik mengidentifikasi tajuk, tetapi karena data pada halaman web hanya cocok /^[0-9]+\. dengan tajuk bagian, tidak perlu untuk memenuhi mereka ( dalam kasus khusus ini). Terima kasih; terutama untuk intro ke getline.. PS. dapat sementara jika?
Peter.O

@ fred geekosaur dan saya pergi dengan deskripsi dalam pertanyaan, bukan oleh data di situs web. Tata letak akan tergantung pada mesin rendering HTML yang digunakan untuk mengkonversi ke teks; bagian di mana ini diberikan dari halaman web sebenarnya tidak relevan dengan pertanyaan. ||| whileapakah ada dalam kasus input berisi 1.\n2.\n\n(di mana \nbaris baru): 2.harus dikenali di baris header. Ini tidak akan terjadi di sini, tetapi saya mendukungnya dalam kode saya untuk membuatnya lebih umum (dan mencocokkan spesifikasi dalam pertanyaan dengan lebih ketat).
Gilles 'SANGAT berhenti menjadi jahat'
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.