Dividindo arquivos de texto baseados em uma expressão regular

12

Eu tenho um arquivo de texto que eu quero dividir em 64 partes desiguais, de acordo com os 64 hexagramas do Yi Jing. Como a passagem para cada hexagrama começa com alguns dígitos, um período e duas novas linhas, o regex deve ser bem fácil de escrever.

Mas como dividir o arquivo de texto em 64 novos arquivos de acordo com essa regex? Parece mais uma tarefa para perl . Mas talvez haja uma maneira mais óbvia de que eu esteja totalmente ausente.

    
por ixtmixilix 26.06.2011 / 21:09

3 respostas

16

Isso seria csplit , exceto que a regex tem que ser uma única linha. Isso também torna sed difícil; Eu iria com Perl ou Python.

Você pode ver se

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

é bom o suficiente para seus propósitos. ( csplit requer um POSIX BRE, por isso não pode usar \d ou + , entre outros.)

    
por 26.06.2011 / 21:16
4

Acho que a melhor maneira é awk e gawk .

awk

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

-F especificará o separador de campos para cada linha. É uma regex, aqui usamos vários separadores: ". " e " / " . Assim, uma linha como 1. Ch'ien / The Creative será dividida em três campos: 1 Ch'ien e The Creative . Mais tarde podemos nos referir a esses campos com $n . $0 é a linha inteira.

Em seguida, dizemos ao awk para corresponder as linhas com o padrão ^[0-9]{1,3}[.] Se houver correspondência, atribuímos o valor a x . O valor x será usado como nome de arquivo para print operation. Neste exemplo, usamos "F"$1"("$2").txt" , então a linha 1. Ch'ien / The Creative fornece um nome de arquivo F1(Ch'ien).txt

gawk

No gawk, também podemos acessar o grupo capturado. Então podemos simplificar o comando para:

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

aqui usamos match para capturar os grupos e colocá-los na lista de variáveis ary . $0 é a linha inteira. ary[0] é tudo combinado. ary[1...n] é cada grupo.

perl

Também podemos fazer isso com o perl:

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

Resultados:

> 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

como obter o arquivo de exemplo:

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
    
por 07.06.2017 / 17:18
3

Com o GNU coreutils, você pode usar csplit para dividir um arquivo em partes delimitadas por regexp, como mostrado por geekosaur .

Aqui está um script awk portátil para dividir um arquivo em partes. Ele funciona por

  • chamando getline para lidar com o separador de múltiplas linhas (2 linhas);
  • definindo uma variável outfile para o nome do arquivo para impressão, quando um cabeçalho de seção é encontrado.
BEGIN {outfile="header.txt"}
{
    while (/^[0-9]+\.$/) {
        prev = $0; getline;
        if ($0 == "") outfile = prev "txt";
        print prev >outfile
    }
    print >outfile
}
    
por 27.06.2011 / 00:32