3
votes

Comment joindre plusieurs lignes si le motif correspond à un segment multiple

Mon fichier contient:

sed 'N;s/\n\s*+b//;P;D' file

Je veux traiter le fichier avec quelque chose comme sed , awk , ou quoi que ce soit pour devenir:

segment  
bob is working eating drinking  
linda is studying  
john is reading listening  
segment  
john is driving  
linda is cooking washing  
bob is sleeping snoring  
segment  

J'ai essayé:

segment  
bob is working  
linda is studying  
john is reading  
+b eating  
+b drinking  
+j listening  
segment  
john is driving  
linda is cooking  
bob is sleeping  
+b snoring  
+l washing  
segment  

Cependant, seules les lignes avec + b traitées

J'apprécierais toute aide.


0 commentaires

3 Réponses :


2
votes
$ awk -f tst.awk file
segment
bob is working eating drinking
linda is studying
john is reading listening
segment
john is driving
linda is cooking washing
bob is sleeping snoring
segment

3 commentaires

Excellente solution! BTW, votre script commence par coïncidence avec la suppression des espaces supplémentaires à la fin des lignes comme le mien.


excellente solution Ed Morton, ça marche vraiment! apprécier si vous pouviez expliquer un peu la fonction utilisée dans ce script awk, assez nouveau avec l'appel substr


@WalitGemilang vous êtes les bienvenus. La page de manuel décrit mieux que je ne pourrais ce que fait substr (), voir gnu.org/software/gawk/manual/gawk.html#String-Functions



1
votes

Si perl est votre option, veuillez essayer ce qui suit:

segment
bob is working eating drinking
linda is studying
john is reading listening
segment
john is driving
linda is cooking washing
bob is sleeping snoring
segment

sortie:

perl -ne '
    s/\s+$//;
    if (/^segment/) {
        push(@ary, $_);
        print(join("\n", @ary), "\n");
        undef @ary;
    } elsif (/^(\S)\S*\s+is/) {
        push(@ary, $_);
        $index{$1} = $#ary;
    } elsif (/^\+(\S)\s+(\S+)/) {
        $ary[$index{$1}] .= " $2";
    }
' file.txt
    L'option
  • -n indique à perl d'itérer sur le fichier d'entrée comme awk -n .
  • s / \ s + $ // supprime le (s) caractère (s) de retour à la ligne de fin et les espaces, le cas échéant.
  • La partie if (/ ^ segment /) vide le contenu de @ary et réinitialiser le tableau pour le segment suivant.
  • La prochaine partie elsif (/ ^ (\ S) \ S * \ s + is /) correspond à la ligne comme bob travaille puis ajoutez la ligne dans @ary en mémorisant le index de l'arrary avec l'initiale comme "b".
  • La prochaine partie elsif (/ ^ \ + (\ S) \ s + (\ S +) /) correspond à la ligne comme + b manger puis ajoutez l'action manger à l'élément de @ary indexé via "b".

Je pourrais aussi écrire un script avec awk mais le script serait plus long. Je préfère perl pour sa flexibilité (et sa bizarrerie).
J'espère que cela vous aidera.


0 commentaires

0
votes

Probablement pas la plus courte, mais voici une version sed simple:

sed <file -E '
    :l;
    /(^|\n)segment[ \t]*$/!{
        N;
        s/(^|\n)(.)([^\n]*)[ \t](.*)\n[+]\2[ \t]+([^\n]*)/\1\2\3\5\4/;
        bl;
    }
'
  • s'il ne correspond pas à la ligne de segment,
    • ajouter la ligne suivante à l'espace de motif
    • rechercher les lignes commençant par x et + x et ajouter la queue de la dernière à la première
    • revenir en haut
  • sinon, impression implicite, suppression de l'espace de motif et démarrage du cycle suivant


0 commentaires