Розщеплення текстових файлів на основі регулярного виразу


16

У мене є текстовий файл, який я хочу розділити на 64 нерівні частини, відповідно до 64 гексаграм Йі Цзіна. Оскільки проходження для кожної гексаграми починається з деякої цифри (цифр), періоду та двох нових рядків, регулярний вираз повинен бути досить простим для запису.

Але як насправді розділити текстовий файл на 64 нові файли відповідно до цього регулярного виразу? Здається, це більше завдання для perl. Але, можливо, є більш очевидний спосіб, який я просто повністю пропускаю.

Відповіді:


23

Це було б csplitвинятком того, що регулярний вираз повинен бути одним рядком. Це також sedускладнює; Я б поїхав з Perl або Python.

Ви могли бачити, якщо

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

достатньо хороший для ваших цілей. ( csplitпотрібен POSIX BRE, тому він не може використовуватись, \dабо +серед інших.)


Дякую, @geekosaur Це справно працювало, хоча мені довелося змінити його на {63}.
ixtmixilix

1
Отже, '\.'не буде працювати також?
Вануан

4

Я думаю, що найкращий спосіб є awkі є gawk.

awk

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

-Fбуде вказати роздільник полів для кожного рядка. Це регулярний вираз, тут ми використовуємо кілька сепараторів: ". "і " / ". Таким чином, такий рядок 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. $0- це весь рядок. ary[0]чи все відповідає. ary[1...n]- кожна група.

перл

Ми також можемо це зробити за допомогою 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

Використовуючи GNU coreutils, ви можете використовувати csplitдля розбиття файлу на шматки, розміщені з регулярними виразками , як показано geekosaur .

Ось портативний скрипт для розбиття файлу на шматки. Це працює за

  • заклик getlineрозібратися з багаторядковим (2-лінійним) роздільником;
  • встановлення змінної outfileна ім'я файлу для друку, коли виникає заголовок розділу.
BEGIN {outfile="header.txt"}
{
    while (/^[0-9]+\.$/) {
        prev = $0; getline;
        if ($0 == "") outfile = prev "txt";
        print prev >outfile
    }
    print >outfile
}

Це в принципі працює , але заголовок розділу фактичних даних веб-сторінок не є таким, як представлений регулярним виразом (аналогічно з відповіддю geekosaur). На початку nunber. йде текст, який містить косу рису /. Я впевнений, що згаданий two newlines ixtmixilix - це 2 порожні рядки, які передують числовому ідентифікатору і більш конкретно ідентифікують заголовок, але оскільки дані на веб-сторінці збігаються лише /^[0-9]+\. у заголовках розділів, не потрібно їх задовольняти ( у цьому конкретному випадку). Спасибі; особливо для вступу до getline.. PS. може при цьому, якщо?
Пітер.O

@fred geekosaur і я пішов за описом у питанні, а не за даними на веб-сайті. Макет залежатиме від механізму візуалізації HTML, який використовується для перетворення тексту; частина, де це зроблено з веб-сторінки, фактично не має значення для питання. ||| whileчи є на випадок, якщо вхід містить 1.\n2.\n\n(де \nє нові рядки): 2.обов'язково розпізнається в рядку заголовка. Тут це не відбудеться, але я підтримую його у своєму коді, щоб зробити його більш загальним (і суворіше відповідати специфікації у питанні).
Жил 'ТАК - перестань бути злим'
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.