Fractionnement de fichiers texte basés sur une expression régulière

16

J'ai un fichier texte que je veux diviser en 64 parties inégales, selon les 64 hexagrammes du Yi Jing. Comme le passage pour chaque hexagramme commence par un ou plusieurs chiffres, un point et deux nouvelles lignes, l'expression régulière devrait être assez facile à écrire.

Mais comment puis-je réellement diviser le fichier texte en 64 nouveaux fichiers selon cette expression régulière? Cela semble être plus une tâche pour perl. Mais il y a peut-être une façon plus évidente de me manquer totalement.

ixtmixilix
la source

Réponses:

23

Ce serait csplitsauf que l'expression régulière doit être une seule ligne. Cela rend également seddifficile; J'irais avec Perl ou Python.

Vous pouvez voir si

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

est assez bon pour vos besoins. ( csplitnécessite un BRE POSIX, donc il ne peut pas utiliser \dou +, entre autres.)

geekosaure
la source
Merci, @geekosaur. Cela a parfaitement fonctionné, même si j'ai dû le changer en {63}.
ixtmixilix
1
Alors, ça '\.'ne marchera pas aussi?
Vanuan
4

Je pense que la meilleure façon est awket gawk.

awk

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

-Fspécifiera des champs séparés pour chaque ligne. Il s'agit d'une expression régulière, ici nous utilisons plusieurs séparateurs: ". "et " / ". Ainsi une ligne comme 1. Ch'ien / The Creativesera divisée en 3 champs: 1 Ch'ienet The Creative. Plus tard, nous pouvons nous référer à ces champs avec $n. $0est toute la ligne.

Nous demandons ensuite à awk de faire correspondre les lignes avec le motif. ^[0-9]{1,3}[.]S'il y a correspondance, nous attribuons ensuite une valeur à x. La valeur x sera utilisée comme nom de fichier pour l' printopération. Dans cet exemple, nous utilisons "F"$1"("$2").txt"donc la ligne 1. Ch'ien / The Creativedonne un nom de fichierF1(Ch'ien).txt

rester bouche bée

Dans gawk, nous pouvons également accéder au groupe capturé. Nous pouvons donc simplifier la commande pour:

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

ici, nous utilisons matchla capture des groupes et les mettons dans la liste des variables ary. $0est toute la ligne. ary[0]est tout assorti. ary[1...n]est chaque groupe.

perl

On peut aussi le faire avec perl:

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

Résultats:

> 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

comment obtenir l'exemple de fichier:

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
Wang
la source
3

Avec GNU coreutils, vous pouvez utiliser csplitpour diviser un fichier en morceaux délimités par des expressions rationnelles, comme le montre geekosaur .

Voici un script awk portable pour diviser un fichier en morceaux. Cela fonctionne par

  • appeler getlinepour traiter le séparateur multiligne (2 lignes);
  • définir une variable outfilesur le nom du fichier sur lequel imprimer, lorsqu'un en-tête de section est rencontré.
BEGIN {outfile="header.txt"}
{
    while (/^[0-9]+\.$/) {
        prev = $0; getline;
        if ($0 == "") outfile = prev "txt";
        print prev >outfile
    }
    print >outfile
}
Gilles 'SO- arrête d'être méchant'
la source
Cela fonctionne en principe , mais l'en-tête de section des données de la page Web réelle n'est pas représenté par l'expression régulière (de même avec la réponse du geekosaure). Le début nunber. est suivi d'un texte contenant une barre oblique /. Je suis presque sûr que les two newlines ixtmixilix mentionnés sont les 2 lignes vides qui précèdent l'identifiant numérique et identifieraient plus spécifiquement l'en-tête, mais comme les données sur la page Web ne correspondent que /^[0-9]+\. dans les en-têtes de section, il n'est pas nécessaire de les traiter ( dans ce cas particulier). Merci; surtout pour l'intro de getline.. PS. peut tout être si?
Peter.O
@fred geekosaur et moi sommes allés par la description dans la question, pas par les données sur le site Web. La mise en page dépendra du moteur de rendu HTML utilisé pour convertir en texte; la partie où cela est rendu à partir d'une page Web est en fait sans rapport avec la question. ||| whileest là si l'entrée contient 1.\n2.\n\n(où \nsont des sauts de ligne): le 2.doit être reconnu dans la ligne d'en-tête. Cela ne va pas se produire ici, mais je le soutiens dans mon code pour le rendre plus général (et correspondre plus strictement aux spécifications de la question).
Gilles 'SO- arrête d'être méchant'