Trier une section d'un fichier

8

Est-il possible de trier entre deux chaînes dans un gros fichier?

Par exemple, le fichier actuel est comme:

    0cf  Front Brake
    0d0  Rear Brake
    0ce  Handle Bars
HUT 03  VR Controls
    009  Vest
    001  Belt
    002  Body Suit
    020  Stereo Enable
    003  Flexor
    007  Hand Tracker
    004  Glove
    006  Head Mounted Display
    008  Oculometer
    00a  Animatronic Device
    000  Unidentified
    021  Display Enable
    005  Head Tracker
HUT 04  Sport Controls
    000  Unidentified
    002  Golf Club
    001  Baseball Bat

Et la sortie souhaitée est la suivante:

    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Ici, la section HUT 03 VR Controls et HUT 04 Sports Controls est triée.

Dans un fichier donné, les en-têtes de section commencent par des caractères sans espace tandis que le contenu de la section commence toujours par un espace ou une tabulation. Étant donné que ce fichier contient plus de 100 sections, il ne sera pas possible de coder en dur le nom de la section dans le script / la commande

SHW
la source
Les sections sont-elles sur des numéros de ligne fixes ou définies par des modèles?
Sparhawk
Les en-têtes de section commencent comme un premier caractère de ligne, tandis que son contenu commence par un espace / tabulation. Les sections ne sont pas sur des nombres fixes.
SHW
Souhaitez-vous trier une seule section (selon le titre de la question et le texte) ou toutes les sections?
Kusalananda
@Kusalananda Je suis d'accord que la question est ambiguë sur ce point; l'exemple de sortie montre cependant toutes les sections (ou parties de celles-ci) en cours de tri.
Stephen Kitt
Je ne dirais pas que "HUT" utilise des caractères hexadécimaux.
jlliagre

Réponses:

7

En Python:

#!/usr/bin/python3

with open("file.txt", "r") as ins:
    lines = []
    for line in ins:
        if line.startswith((" ", "\t")):
            lines.append(line)
        else:
            lines.sort()
            print(*lines, end = "", sep = "")
            print(line, end = "")
            lines = []
    lines.sort()
    print(*lines, end = "", sep = "")

Cela trie toutes les sections (séparément), pas seulement celles entre deux lignes spécifiques.

Stephen Kitt
la source
Superbe! C'est un coup de maître.
SHW
6

Pour le plaisir, voici un moyen de trier une seule section en utilisant ex:

ex file <<%
/HUT
+1,/HUT/-1!sort
w file.sorted
q
%
jlliagre
la source
6
$ awk 'BEGIN { OFS="\t"; s=0 } /^[^[:blank:]]/ { print ++s "\b", $0; next } { print s, $0 }' file | sort -n | cut -f 2-
    0ce  Handle Bars
    0cf  Front Brake
    0d0  Rear Brake
HUT 03  VR Controls
    000  Unidentified
    001  Belt
    002  Body Suit
    003  Flexor
    004  Glove
    005  Head Tracker
    006  Head Mounted Display
    007  Hand Tracker
    008  Oculometer
    009  Vest
    00a  Animatronic Device
    020  Stereo Enable
    021  Display Enable
HUT 04  Sport Controls
    000  Unidentified
    001  Baseball Bat
    002  Golf Club

Cela permet awkd'ajouter un nombre (et un séparateur de tabulation) devant chaque ligne correspondant à la section dans laquelle se trouve cette ligne. Pour les en-têtes de section, nous ajoutons un nombre suivi d'un caractère de retour arrière (uniquement parce que le retour arrière trie avant les tabulations). Ensuite, nous trions simplement les données résultantes sur ces numéros avant de les supprimer et les séparateurs d'onglets ajoutés.

Les en-têtes de section sont détectés en recherchant des caractères non vides au début de la ligne.

Kusalananda
la source
1
Agréable! J'aime particulièrement le truc de retour arrière.
Stephen Kitt
1
Avec cette approche, vous pouvez également utiliser le numéro de section (après le HUTchamp) comme préfixe, pour trier également les sections.
Stephen Kitt,
3

Vous pourriez obtenir awket sortcoopérer pour faire le travail.

awk '
    /^[[:blank:]]/{print | "sort"; next}
    {close("sort"); print}; 
    END{close("sort")}
' file
  • Canalisez chaque ligne de contenu dans sort
  • Appelez closele sortlorsqu'un marqueur de section est rencontrée; cela provoque sortle vidage de sa sortie vers la sortie standard et la sortie
  • Imprimer le marqueur de section
  • Une nouvelle instance de sortprend le relais des lignes de contenu suivant le marqueur de section
  • Appelez closeà sortla fin pour prendre soin de contenu de fuite
iruvar
la source
1

Pour de telles tâches, je trouve souvent fastidieux d'écrire un script. Si cela ne doit être fait qu'une seule fois et peut-être pour quelques fichiers, cela peut être fait très bien en utilisant une macro si vous ouvrez le fichier vimet tapez:

  • GoFAKE SECTION<ESC>: ajoutez une fausse section à la fin et assurez-vous qu'elle se trouve au début de la ligne (vous l'avez peut-être activée cindentou autoindentactivée). Cela est également nécessaire pour trier la dernière section.
  • gg: retour au début du fichier, puis le fichier commence par une section descend une ligne avec j
  • qq: démarrer l'enregistrement d'une macro pour s'enregistrer q
  • v: démarrer la sélection
  • /^\S\+<Enter>: recherchez le début de la section suivante
  • k: d'une ligne
  • :!sort<Enter: trier la section
  • nj: aller au premier élément de la section suivante
  • q: arrêter l'enregistrement de la macro
  • @q: répéter la macro
  • 100@@: répéter la macro plusieurs fois (jusqu'à ce qu'il ne reste plus de sections)
  • dd: supprime la dernière ligne du fichier (le FAKE SECTION)

Vous souhaiterez peut-être :set lazyredrawaccélérer l'exécution des macros.

MarcDefiant
la source