根据正则表达式拆分文本文件


16

根据《易经》的64个卦,我有一个文本文件,希望将其分成64个不相等的部分。由于每个卦的开头都是一些数字,一个句点和两个换行符,因此正则表达式应该很容易编写。

但是,实际上如何根据此正则表达式将文本文件拆分为64个新文件?似乎更像是一项任务perl。但是也许有一种更明显的方式让我完全迷失了。

Answers:


23

这将是csplit除了正则表达式必须是一个单行。这也sed很困难;我会选择Perl或Python。

你看是否

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

足以满足您的目的。(csplit需要POSIX BRE,因此它不能使用\d+。)


谢谢,@ geekosaur。尽管我不得不将其更改为{63},但它的运行效果很好。
ixtmixilix 2011年

1
所以,'\.'也行不通吗?
Vanuan

4

我认为最好的方法是awkgawk

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'ienThe 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中,我们还可以访问捕获的组。因此,我们可以将命令简化为:

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将文件分成以regexp分隔的片段,如geekosaur所示

这是一个可移植的awk脚本,用于将文件分成多个部分。它的工作原理

  • 调用getline处理多行(两行)分隔符;
  • 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 的介绍。可以吗?
Peter.O 2011年

@fred geekosaur和我按问题的说明,而不是按网站上的数据。布局将取决于用于转换为文本的HTML渲染引擎。从网页上呈现出来的部分实际上与问题无关。||| while是否包含输入内容1.\n2.\n\n(其中\n有换行符):2.必须在标题行中识别。它不会在这里发生,但是我在代码中支持它以使其更通用(并更严格地匹配问题中的规范)。
吉尔(Gilles)“所以,别再邪恶了”,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.