Diviser le file d'input avec des sauts de ligne

J'essaye d'insert des sauts de ligne sur un dossier basé sur les mêmes noms qui se trouve être le deuxième champ dans mon dossier. Donc, mon file d'input est comme ci-dessous.

17412193|name1|organization 43979400|name1|organization 1405541|name2|organization 53595498|name2|organization 50439202|name2|organization 54678379|name3|Not Found 21757330|name3|organization 

Donc, j'essaie d'get la sortie comme,

 17412193|name1|organization 43979400|name1|organization ###linebreak inserted here 1405541|name2|organization 53595498|name2|organization 50439202|name2|organization ###linebreak inserted here 54678379|name3|Not Found 21757330|name3|organization ###linebreak inserted here 

J'utilise ce saut de ligne pour split le file d'input pour regrouper les noms similaires set. J'appliquerais plus tard un algorithm de similarité sur ces noms groupés. Donc, pour l'exemple ci-dessus, après la sortie j'appliquerais l'algorithm de similarité sur 3 paires de noms.

En supposant que votre file est sortingé / groupé par le 2ème champ déjà

 awk -F '|' 'NR>1 && $2 != prev {print ""} {prev=$2; print}' file 

Voici une solution Perl insensible à la casse:

 perl -F'\|' -lape 'unless($F[1]=~/^$pre$/i || $.==1){print ""}; $pre=$F[1]' file 

Explication:

  • Le -a sépare les lignes d'input dans le tableau @F , faisant perl agir comme awk.
  • Le -F est le séparateur de champs
  • -p signifie imprimer chaque ligne d'input
  • -l ajoute un \n à chaque appel d'printing, donc print "" imprime une nouvelle ligne.
  • unless($F[1]=~/^$pre$/i || $.==1) si le second champ est le même que celui de la ligne précédente (le i in //i rend la correspondance insensible à la casse ), ou à less que ce soit la première ligne.
  • $pre=$F[1] : enregistrez cette deuxième ligne comme $pre .

@GlennJackman a suggéré une version légèrement différente dans les commentaires qui sera probablement plus rapide pour les files plus volumineux:

 perl -F'\|' -lape 'unless(lc($F[1]) eq lc($pre) || $.==1){print ""}; $pre=$F[1]' file 

Une solution Perl un peu plus courte:

 perl -pe 'print "\n" if ($l =~ /name\d+/ && $_ !~ /$&/);$l=$_;' input 
  • si la dernière ligne ( $l ) était le name\d+ et la ligne actuelle ne correspond pas à la dernière, puis imprimer la nouvelle ligne
  • affecter la ligne courante à $l

Une solution plus générale

 perl -pe 'print "\n" if ($l =~ /\|([^\|]+)/ && $_ !~ /$1/);$l=$_;' input 
 #!/bin/sh #shell basics, POSIX compliant (set -f ;IFS='| ' ; set -- $(cat) ; while [ -n "$3" ] ;do { [ "${t=$2}" != "$2" ] && echo && t=$2 printf '%s|%s|%s\n' "$1" "$2" "$3" ; shift 3 } ; done )<<\SAMPLE 17412193|name1|organization 43979400|name1|organization 1405541|name2|organization 53595498|name2|organization 50439202|name2|organization 54678379|name3|Not Found 21757330|name3|organization SAMPLE Output 17412193|name1|organization 43979400|name1|organization 1405541|name2|organization 53595498|name2|organization 50439202|name2|organization 54678379|name3|Not Found 21757330|name3|organization