1
votes

Faire des alternances sed regex suivre la priorité de gauche à droite?

J'essaie d'utiliser une regex pour formater un binaire de xxd -b , mais pour le démontrer simplement, je vais vous montrer ce que j'attends de se produire:

Regex à supprimer: /1x|1.*/

Texte: 1x21y3333333313333 -> 2

Où tout les occurrences de 1x sont supprimées, puis tout ce qui commence au premier 1 qui apparaît doit être supprimé. Ce qui se passe devrait être immédiatement évident, mais sinon, jouez avec ça . La clé est que si 1x correspond, le reste du modèle doit être abandonné.

Voici la sortie de echo "AA" | xxd -b (le bindump de AA\n):

0000000:100000110000010001010

Mon objectif est de 1. supprimer le premier 0 pour chaque byte (ascii = 7 bits) et 2. supprimez le reste de la chaîne pour ne conserver que le binaire réel. Je l'ai donc envoyé dans sed 's / 0 // g' :

0000000:

Ajout de la deuxième étape, sed -E ' s / 0 | . * // g ':

0000000:100000110000010001010                             AA.

Évidemment, j'espère obtenir à la place:

0000000: 01000001 01000001 00001010                             AA.

Choses J'ai essayé mais je n'ai pas fait le travail:

  • xxd peut prendre -g0 pour fusionner les colonnes, mais il conserve le premier zéro dans chaque octet (les caractères occupent chacun un octet, pas 7 bits) li>
  • -r

Je vais utiliser perl à la place en attendant, mais ce comportement me déroute et peut-être qu'il y a une raison (leçon) ici?


0 commentaires

3 Réponses :


2
votes

Si je comprends bien votre question, cela produit ce que vous voulez:

$ echo "AA" | xxd -b | sed -E 's/ 0//g; s/ .*//'
00000000:100000110000010001010

Le changement clé ici est l'utilisation de deux espaces devant . * donc que cela ne correspond qu'à la partie que vous souhaitez supprimer.

Sinon, nous pouvons d'abord supprimer le blanc-zéro:

$ echo "AA" | xxd -b | sed -E 's/ 0|  .*//g'
00000000:100000110000010001010


1 commentaires

J'aime le deuxième extrait, ça m'a fait me gifler. Au lieu de faire les alternances dans une regex, je pourrais simplement la diviser!



1
votes

Essayez ce qui suit:

 s/ 0| [^0].*//g

La raison du comportement observé est que POSIX ordonne aux moteurs de suivre la norme de correspondance la plus longue possible . Donc, tant que le deuxième côté de l'alternance est plus long que le premier, même en étant le deuxième dans l'ordre, il correspond plus tôt.


4 commentaires

Oh mon dieu, tu as raison. Après avoir recherché "posix plus longue correspondance" et parcouru deux liens, il est apparemment indiqué ici : "Si le modèle permet un nombre variable de caractères correspondants et qu'il y a donc plus d'une séquence de ce type à partir de ce point, la plus longue séquence de ce type est mise en correspondance. [...] l'ERE" (wee | week ) (knights | night) "correspond aux dix caractères de la chaîne" weeknights "." Certainement contre-intuitif après avoir utilisé beaucoup de regex modernes ...


Bien que cette réponse corresponde à la chaîne d'entrée donnée, elle échouera si une séquence démarre, par ex. avec 1 . La bonne façon est la deuxième approche de John1024.


@revo Ma mise à jour de stackoverflow.com/a/216228/6309 n'était pas assez complète?


@VonC C'était. Je voulais attirer plus d'attention pour impliquer plus de gens. Malheureusement, j'ai oublié de donner la prime en fin de période.



0
votes

essayé sur gnu sed

sed -E 's/\s+(0|[a-z.]+)//ig'


0 commentaires