Supposons qu'il y ait du texte dans un fichier:
(bookmarks
("Chapter 1 Introduction 1" "#1"
("1.1 Problem Statement and Basic Definitions 23" "#2")
("Exercises 31" "#30")
("Notes and References 42" "#34"))
)
Je veux ajouter 11 à chaque numéro suivi d'un "
dans chaque ligne s'il y en a un, c'est-à-dire
(bookmarks
("Chapter 1 Introduction 12" "#12"
("1.1 Problem Statement and Basic Definitions 34" "#13")
("Exercises 42" "#41")
("Notes and References 53" "#45"))
)
Voici ma solution en utilisant GNU AWK et regex:
awk -F'#' 'NF>1{gsub(/"(\d+)\""/, "\1+11\"")}'
c'est à dire, je veux remplacer (\d+)\"
par \1+10\"
, où \1
est le groupe représentant (\d+)
. Mais ça ne marche pas. Comment puis-je le faire fonctionner?
Si gawk n'est pas la meilleure solution, quoi d'autre peut être utilisé?
Réponses:
Essayez ceci (gawk est nécessaire).
Testez avec votre exemple:
Notez que cette commande ne fonctionnera pas si les deux nombres (par exemple 1 "et" # 1 ") sont différents. Ou s'il y a plus de nombres sur la même ligne avec ce modèle (par exemple 23" ... 32 "..." # 123 ") sur une seule ligne.
MISE À JOUR
Étant donné que @Tim (OP) a déclaré que le nombre suivi de la
"
même ligne pourrait être différent, j'ai apporté quelques modifications à ma solution précédente et l'ai fait fonctionner pour votre nouvel exemple.BTW, d'après l'exemple, je pense que cela pourrait être une table de structure de contenu, donc je ne vois pas comment les deux nombres pourraient être différents. Le premier serait le numéro de page imprimé, et le deuxième avec # serait l'index de la page. Ai-je raison?
Quoi qu'il en soit, vous connaissez le mieux vos besoins. Maintenant la nouvelle solution, toujours avec gawk (je décompose la commande en lignes pour en faciliter la lecture):
tester avec votre nouvel exemple:
EDIT2 basé sur le commentaire de @Tim
Vous avez raison pour le séparateur à la fois en entrée et en sortie. Il définit le séparateur comme:
Il y a deux guillemets doubles, car il est plus facile d'attraper les deux nombres que vous souhaitez (en fonction de votre exemple d'entrée).
Exactement!
Il s'agit de http://www.gnu.org/s/gawk/manual/html_node/String-Functions.html . vous pouvez lire pour obtenir une utilisation détaillée de gensub.
la source
awk -F'#'
, il semble que vous ne souhaitiez effectuer la modification sur la pièce qu'après le '#'?FS=OFS="\" \"#"
signifie que le séparateur de champ à la fois en entrée et en sortie est guillemet double, espace, guillemet double et #? pourquoi spécifier deux fois le guillemet double? (2) dans/.* ([0-9]+)$/
,$
signifie la fin de la chaîne? (3) dans le troisième argument de gensub (), quelle est la différence entre"g"
et"G"
?Contrairement à presque tous les outils qui fournissent des substitutions d'expression rationnelle, awk n'autorise pas les références arrières, comme
\1
dans le texte de remplacement. GNU Awk donne accès aux groupes correspondants si vous utilisez lamatch
fonction , mais pas avec~
ousub
ougsub
.Notez également que même s'il
\1
était pris en charge, votre extrait de code ajouterait la chaîne+11
, sans effectuer de calcul numérique. De plus, votre expression rationnelle n'est pas tout à fait juste, vous faites correspondre des choses comme"42""
et non"#42"
.Voici une solution awk (avertissement, non testé). Il n'effectue qu'un seul remplacement par ligne.
Ce serait plus simple en Perl.
la source
awk
peut le faire, mais ce n'est pas direct, même en utilisant le renvoi.GNU awk a une rétro-référence (partielle), sous forme de gensub .
Les instances de
123"
sont temporairement enveloppées\x01
et\x02
pour les marquer comme non modifiées (poursub()
. CoOu vous pouvez simplement parcourir les candidats qui changent de boucle au fur et à mesure, auquel cas, la référence arrière et les "crochets" ne sont pas nécessaires; mais le suivi de l'index des caractères est nécessaire.
Voici une autre manière, en utilisant
gensub
and arraysplit
et\x01
comme délimiteur de champ (pour split ) .. \ x02 marque un élément de tableau comme candidat pour l'addition arithmétique.la source
"\x01\\1\"\x02"
signifie? Je ne comprends toujours pas\x01
et\x02
. (2) Quelle est la différence entre le retour$0
pargensub
et$0
le dernier argumentgensub
?\x01
et\x02
sont utilisées comme marqueurs de substitution. Ces valeurs sont très peu susceptibles d'être dans une normale fichier texte, ils sont également « très » en sécurité à utiliser (ie. Rencontre pas d' un affrontement avec les pré-existants) .. Ils ne sont que des étiquettes temporaires .. Re$0=gensub(... $0)
.. voir ce lien String-Manipulation Functions , mais en résumé: It (gensub) renvoie la chaîne modifiée comme résultat de la fonction et la chaîne cible d'origine n'est pas modifiée. ... Le$0=
modifie simplement la cible d'origine ..Comme les solutions en (g) awk semblent devenir assez complexes, je voulais ajouter une solution alternative en Perl:
Explication:
-w
active les avertissements (qui vous avertiront d'éventuels effets indésirables).-p
implique une boucle autour du code qui fonctionne de manière similaire à sed ou awk, sauver chaque ligne d'entrée automatiquement dans la variable par défaut,$_
.-e
indique à perl que le code du programme suit sur la ligne de commande, pas dans un fichier de script.s/.../.../
) activée$_
, où une séquence de chiffres, si elle est suivie d'un"
, sera remplacée par la séquence, interprétée comme un nombre dans l'addition, plus 11.(?=pattern)
anticipation positive de largeur nulle recherche le"
sans le prendre en compte, nous n'avons donc pas à le répéter dans le remplacement. La variable MATCH$&
dans le remplacement ne contiendra alors que le nombre./e
modificateur de l'expression régulière indiqueperl
«d'exécuter» le remplacement comme code au lieu de le prendre comme chaîne./g
modificateur rend le remplacement "global", en le répétant à chaque match de la ligne.La variable MATCH
$&
sera malheureusement préjudiciable aux performances du code dans les versions Perl antérieures à 5.20. Une solution plus rapide (et pas beaucoup plus complexe) utiliserait$1
plutôt le regroupement et la référence arrière :Et si l'assertion prospective semble trop déroutante, vous pouvez également remplacer explicitement le guillemet:
la source