แยกไฟล์ข้อความตามนิพจน์ปกติ


16

ฉันมีไฟล์ข้อความที่ฉันต้องการแยกออกเป็น 64 ส่วนที่ไม่เท่ากันตาม 64 hexagrams ของ Yi Jing เนื่องจากเนื้อเรื่องสำหรับแต่ละแฉกเริ่มต้นด้วยหลักบางจุดระยะเวลาและบรรทัดใหม่สองบรรทัด regex ควรเขียนง่าย

แต่ฉันจะแยกไฟล์ข้อความเป็น 64 ไฟล์ใหม่ตาม regex นี้ได้อย่างไร ดูเหมือนว่าเป็นงานที่ต้องทำperlอีกมาก แต่อาจจะมีวิธีที่ชัดเจนกว่าที่ฉันเพิ่งหายไปโดยสิ้นเชิง

คำตอบ:


23

นี่จะcsplitยกเว้นว่า regex ต้องเป็นบรรทัดเดียว นั่นก็ทำให้sedยากเช่นกัน ฉันจะไปกับ Perl หรือ Python

คุณสามารถดูว่า

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

ดีพอสำหรับวัตถุประสงค์ของคุณ ( csplitต้องมี POSIX BRE จึงไม่สามารถใช้งาน\dหรือ+อื่น ๆ ได้)


ขอบคุณ @geekosaur มันทำงานได้อย่างสมบูรณ์แม้ว่าฉันจะต้องเปลี่ยนเป็น {63}
ixtmixilix

1
ดังนั้น'\.'จะไม่ทำงานด้วยหรือ
Vanuan

4

ผมคิดว่าวิธีที่ดีที่สุดคือและawkgawk

awk

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

-Fจะระบุตัวคั่นฟิลด์สำหรับแต่ละบรรทัด มันเป็น regex ที่นี่เราใช้ seperators หลายและ". " " / "ดังนั้นสายเหมือน1. Ch'ien / The Creativeจะถูกแบ่งออกเป็น 3 สาขา: และ1 Ch'ien ต่อมาเราสามารถดูข้อมูลเหล่านี้ด้วยThe Creative เป็นทั้งสาย$n$0

จากนั้นเราจะบอก awk เพื่อให้ตรงกับสายที่มีรูปแบบ หากมีตรงกับเราคุ้มค่าแล้วกำหนดที่จะ^[0-9]{1,3}[.] xค่า x จะถูกใช้เป็นชื่อไฟล์สำหรับprintการดำเนินการ ในตัวอย่างนี้เราใช้"F"$1"("$2").txt"เพื่อให้บรรทัด1. Ch'ien / The Creativeให้ชื่อไฟล์F1(Ch'ien).txt

เพ่งพิศ

ในเพ่งพิศเรายังสามารถเข้าถึงกลุ่มที่ถูกจับได้ ดังนั้นเราสามารถทำให้คำสั่งง่ายขึ้นเพื่อ:

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

ที่นี่เราใช้การจับภาพกลุ่มและใส่ลงในรายการตัวแปรmatch เป็นทั้งสาย ทุกอย่างตรงกัน คือแต่ละกลุ่มary$0ary[0]ary[1...n]

Perl

เราสามารถทำได้ด้วย perl:

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

ผล:

> 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

วิธีรับไฟล์ตัวอย่าง:

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

ด้วย coreutils GNU คุณสามารถใช้csplitเพื่อทำลายไฟล์เป็นชิ้น regexp คั่นด้วยการแสดงโดย geekosaur

นี่คือสคริปต์ awk แบบพกพาเพื่อแบ่งไฟล์ออกเป็นชิ้น ๆ มันทำงานโดย

  • การเรียกgetlineเพื่อจัดการกับตัวคั่นหลายบรรทัด (2 บรรทัด)
  • การตั้งค่าตัวแปรoutfileให้เป็นชื่อของไฟล์ที่จะพิมพ์เมื่อพบส่วนหัวของส่วน
BEGIN {outfile="header.txt"}
{
    while (/^[0-9]+\.$/) {
        prev = $0; getline;
        if ($0 == "") outfile = prev "txt";
        print prev >outfile
    }
    print >outfile
}

หลักการนี้ใช้งานได้แต่ส่วนหัวของข้อมูลหน้าเว็บจริงไม่ได้แสดงตาม regex (เช่นเดียวกันกับคำตอบของ geekosaur) ชั้นนำตามด้วยข้อความที่มีการเฉือนnunber. /ฉันค่อนข้างมั่นใจว่าtwo newlines ixtmixilix ที่กล่าวถึงเป็น2 บรรทัดว่างที่อยู่หน้าตัวระบุตัวเลขและจะระบุส่วนหัวโดยเฉพาะ แต่เนื่องจากข้อมูลบนหน้าเว็บตรง/^[0-9]+\. กับส่วนหัวของส่วนเท่านั้นจึงไม่จำเป็นต้องรองรับพวกเขา ( ในกรณีนี้โดยเฉพาะ) ขอบคุณ; โดยเฉพาะอย่างยิ่งสำหรับบทนำของgetline.. PS ในขณะที่สามารถถ้า?
Peter.O

@ เฟร็ด geekosaur และฉันไปตามคำอธิบายในคำถามไม่ใช่โดยข้อมูลในเว็บไซต์ เลย์เอาต์จะขึ้นอยู่กับเอนจิ้นการแสดงผล HTML ที่ใช้ในการแปลงเป็นข้อความ ส่วนที่แสดงผลจากหน้าเว็บนั้นไม่เกี่ยวข้องกับคำถาม ||| whileมีในกรณีที่มีการป้อนข้อมูล1.\n2.\n\n(ที่\nมีขึ้นบรรทัดใหม่): 2.จะต้องได้รับการยอมรับในบรรทัดส่วนหัว มันจะไม่เกิดขึ้นที่นี่ แต่ฉันสนับสนุนในรหัสของฉันเพื่อให้ทั่วไปมากขึ้น (และตรงกับข้อกำหนดในคำถามอย่างเคร่งครัดมากขึ้น)
Gilles 'หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.