Est-il possible avec Gedit ou la ligne de commande de modifier toutes les quatre lignes d'un fichier texte?

11

J'essaie de convertir un fichier texte en une feuille de calcul séparée par des tabulations. Mon fichier texte ressemble à ceci:

Dog
Cat
Fish
Lizard
Wolf
Lion
Shark
Gecko
Coyote
Puma
Eel
Iguana

Avec les fonctions de recherche et de remplacement standard dans Gedit ou LibreOffice, il est facile de remplacer la fin de ligne par un onglet. Mais si je permute simplement les retours chariot pour les onglets, j'obtiendrai ceci:

Dog   Cat   Fish   Lizard   Wolf   Lion   Shark   Gecko   Coyote   Puma   Eel   Iguana

Mais ce que je dois faire, c'est que ça ressemble à ceci:

Dog   Cat   Fish   Lizard
Wolf   Lion   Shark   Gecko  
Coyote   Puma   Eel   Iguana

Alors, puis-je échanger chaque caractère de fin de ligne pour un onglet, sauf pour chaque quatrième ligne?

Je ne sais pas si ce type d'itération conditionnelle peut être effectué avec des expressions régulières dans un programme comme Gedit ou LibreOffice, alors peut-être que cela doit être une sorte de fonction de ligne de commande? Je ne sais même pas quel est le meilleur outil pour commencer.


Mise à jour:

J'ai essayé les commandes suivantes:

sed 'N;N;N;s/\n/\t/g' file > file.tsv

paste - - - - < file > file.tsv

pr -aT -s$'\t' -4 file > file.tsv

xargs -d '\n' -n4 < inputfile.txt

Mais lorsque j'essaie d'ouvrir le tsvfichier résultant dans LibreOffice, les colonnes ne sont pas tout à fait correctes. Je ne sais pas si cela signifie que je n'exécute pas correctement les commandes ci-dessus, ou si je fais quelque chose de mal dans la fonction d'importation de LibreOffice:

Ouverture de TSV à Calc

Juste pour référence, le résultat souhaité devrait ressembler à ceci:

Colonnes appropriées

Questionneur
la source

Réponses:

16

Vous pouvez utiliser un éditeur de ligne de commande tel quesed

sed 'N;N;N;s/\n/\t/g' file > file.tsv

ou, de façon plus programmatique, en ajoutant des caractères de continuation de ligne de barre oblique inverse à chacune des lignes que vous souhaitez joindre à l'aide de l' n skip mopérateur d'adresse de GNU sed et en le suivant avec la ligne unique classique pour joindre les lignes continues:

sed '0~4! s/$/\t\\/' file | sed -e :a -e '/\\$/N; s/\\\n//; ta'

Voir par exemple Sed One-Liners expliqué :

  1. Ajoutez une ligne à la suivante si elle se termine par une barre oblique inverse "\".

    sed -e :a -e '/\\$/N; s/\\\n//; ta'
    

Cependant, à mon humble avis, ce serait plus facile avec l'un des autres utilitaires de traitement de texte standard

paste - - - - < file > file.tsv

(le nombre de -correspondra au nombre de colonnes) ou

pr -aT -s$'\t' -4 file > file.tsv

(vous pouvez omettre le -s$'\tsi cela ne vous dérange pas que la sortie soit séparée par plusieurs onglets).


Le comportement étrange de réimportation que vous observez est presque certainement dû au fait que le fichier d'origine a des fins de ligne CRLF de style Windows. Si vous devez travailler avec des fichiers à partir de Windows, vous pouvez effectuer la conversion dans la commande de différentes manières, par exemple

tr -d '\r' < file.csv | paste - - - -

ou

sed 'N;N;N;s/\r\n/\t/g' file.csv

Le premier supprimera TOUS les retours chariot tandis que le second conservera un CR à la fin de chacune des nouvelles lignes (ce qui peut être ce que vous voulez si l'utilisateur final est sous Windows).

tournevis
la source
1
Une note sur les fins de ligne de style Windows: les outils standard pour convertir entre eux et le style Unix sont dos2unixet unix2dos.
David Foerster
13

Vous pouvez utiliser xargspour toujours regrouper quatre lignes en une, séparées par un seul espace chacune:

xargs -d '\n' -n4 < inputfile.txt

-d '\n'définit le délimiteur d'entrée sur un caractère de nouvelle ligne, sinon il se briserait également sur les espaces. Si vous n'avez de toute façon qu'un seul mot par ligne d'entrée, vous pouvez même l'omettre.
-n4définit le numéro d'argument (le nombre d'éléments d'entrée par ligne de sortie) sur 4.

Production:

Dog Cat Fish Lizard
Wolf Lion Shark Gecko
Coyote Puma Eel Iguana

Ou si vous voulez des tabulations comme séparateurs au lieu d'un espace, vous pouvez les remplacer par la suite. Cependant, si vous aviez des espaces dans vos lignes d'entrée, ceux-ci seraient également remplacés:

xargs -d '\n' -n4 | tr ' ' '\t'

Sortie (regardez en fonction de la largeur de l'onglet du navigateur / terminal):

Dog Cat Fish    Lizard
Wolf    Lion    Shark   Gecko
Coyote  Puma    Eel Iguana
Byte Commander
la source
Cette méthode présente l'avantage de se comporter raisonnablement même lorsque le nombre total de lignes d'entrée n'est pas un multiple de quatre.
Eliah Kagan
3

Vous pouvez également utiliser:

awk -v ORS="" '{print $1; print NR%4==0?"\n":"\t"}' file > file.tsv 

Les deux variables intégrées awk sont:

  • ORS: O utput R ECORD S eparator (default = saut de ligne). Il est ajouté à la fin de chaque commande d'impression.
  • NR: N mbre de courant R oe awk traite.

Cette commande affichera, pour chaque ligne, le contenu de la première (et ici uniquement) colonne. Ensuite, il choisit d'ajouter une nouvelle ligne ou un onglet en testant le reste de la division de NRpar 4.

arauk
la source
3

Une autre awkapproche la plus courte :

awk '{printf $0 (NR%4?"\t":"\n")}' infile

Ce printf la seule colonne suivie suivant et suivant et ... et un onglet \tcaractère après chaque mais printf un \ncaractère ewline lorsque N mbre de R ECORD a été le facteur de 4 (où NR%4retournera 0 (false) qui est ce que l' opérateur ternaires condition(s)?when-true:when-falsefait.)

αғsнιη
la source
3

Ma solution serait d'utiliser la combinaison de sedet sed. Tout d'abord, vous pouvez marquer chaque quatrième ligne avec un caractère spécial, par exemple >, en utilisant cette solution:

Dans ce cas, vous voulez commencer à partir de la ligne 5 et marquer toutes les 4 lignes après. Dans GNU, sedcela peut être donné comme une adresse 5~4. Vous pouvez utiliser cette commande:

sed '5~4s/^/>/' file1 > file2

Ensuite, vous devez supprimer les sauts de ligne, ce qui peut être fait avec une sedboucle:

sed ':a;N;s/\n/ /;ba' file2 > file3

Il existe des moyens plus simples de convertir les sauts de ligne en un autre caractère, par exemple avec tr:

tr '\n' ' ' < file2 > file3

De toute façon, la combinaison des deux donne

Dog   Cat   Fish   Lizard   >Wolf   Lion   Shark   Gecko   >Coyote   Puma   Eel   Iguana

(la sedversion laisse une nouvelle ligne de fin, tandis que la trversion ne le fait pas)

Après cela, il vous suffit de convertir les caractères spéciaux que vous avez insérés en retours à la ligne; voir par exemple Convertir un fichier délimité par des tabulations pour utiliser des retours à la ligne . Dans ce cas, >passez aux sauts de ligne:

sed 'y/>/\n/' file3 > outfile

La ycommande remplit la même fonction que la trtransformation d'un caractère en un autre, mais vous pouvez également utiliser la scommande ici. Avec s, vous devez gopérer sur chaque match de la ligne ( sed 's/>/\n/g').

Plutôt que de créer deux fichiers intermédiaires, vous pouvez utiliser des canaux:

$ sed '5~4s/^/>/' file | sed ':a;N;s/\n/ /;ba' | sed 'y/>/\n/'
Dog Cat Fish Lizard 
Wolf Lion Shark Gecko 
Coyote Puma Eel Iguana

Si les espaces de fin posent problème, vous pouvez ajouter une autre commande pour les supprimer:

| sed 's/ $//'
spaceman117X
la source
2

Par souci d'exhaustivité, voici une solution bash pure:

#!/usr/bin/env bash

sep=$'\t'

while read one \
      && read two \
      && read three \
      && read four
do
  printf "%s\n" "$one$sep$two$sep$three$sep$four"
done

Fonctionne également avec les espaces, en supposant qu'il IFSest correctement défini (ce qu'il devrait par défaut, AFAIK). De plus, je pense que cela pourrait même être un script shell portable et fonctionner avec n'importe quel shell compatible POSIX.

Daniel Jour
la source
1
Ce n'est pas portable pour les shells compatibles POSIX en général, car la $' 'forme de citation n'est pas requise par POSIX. Par exemple, dans dash(qui fournit shpar défaut sur Ubuntu), exécuter printf '%s\n' $'a\tb'uniquement les sorties $a\tb. Cela ne signifie pas que ce n'est pas utile cependant; cela fonctionne en bash. Cependant, comme pour certaines des autres solutions proposées par les utilisateurs, cela produit une sortie incomplète si le nombre de lignes d'entrée n'est pas un multiple de quatre. Aussi, je recommande d'utiliser read -r, car il n'y a aucune raison de penser que l'expansion des échappements antislash dans le fichier d'entrée est souhaitée ici.
Eliah Kagan
Vous pourriez simplement faireprintf '%s\t%s\t%s\t%s\n' "$one" "$two" "$three" "$four"
terdon
2

Une macro vim (enregistrée avec q) pourrait appliquer votre opération, puis sauter trois lignes. Ensuite, vous exécutez cette macro n fois.

par exemple:

qq $ J i <TAB> <ESC> $ J i <TAB> <ESC> $ J i <TAB> <ESC> ^^ j qq 100 @q
rackandboneman
la source
2

Puisque vous avez demandé une solution Gedit, quelque chose comme ça devrait fonctionner:

Trouver:

(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+(\w+)[\r\n]+

Remplacer par:

\1\t\2\t\3\t\4\n

Assurez-vous que la case à cocher pour les expressions régulières est cochée.

Comment ça fonctionne:

La première étape consiste à rechercher une série de caractères de mot, avec \ w +, et à capturer les résultats dans la variable \ 1 en enveloppant les parenthèses autour de l'expression:

(\w+)

Ensuite, nous recherchons une série de caractères de fin de ligne, \ r et \ n, ou CR et LF. Étant donné que les fichiers au format Windows utilisent les deux, nous créons une classe de caractères en enveloppant ces deux caractères entre crochets. Le plus permet de rechercher un ou plusieurs caractères:

[\r\n]+

Enfin, nous répétons cela 3 fois de plus, en stockant chaque mot suivant dans les variables \ 2, \ 3 et \ 4. Cela rend notre remplacement par l'expression simple. Nous avons juste besoin de placer des caractères de tabulation, \ t, et un nouveau caractère de ligne, \ n, aux endroits appropriés pour la mise en forme dont vous avez besoin.

Jason Wood
la source