Comment remplacer tous les espaces vides entre crochets avec un trait de soulignement en utilisant sed?

StackOverflow https://stackoverflow.com/questions/4503535

  •  12-10-2019
  •  | 
  •  

Question

Je me suis dit que pour tourner [un nom] dans [some_name] Je dois utiliser l'expression suivante:

s/\(\[[^ ]*\) /\1_/

i.e.. créer une capture d'backreference pour tout ce qui commence par un littéral « [ » qui contient un certain nombre de caractères non espace, suivi d'un espace, d'être remplacés par les caractères non espace suivi d'un trait de soulignement. Ce que je ne sais pas comment est encore bien de modifier cette expression de sorte qu'il fonctionne pour tous dans les accolades souligne par exemple [Quelques mots] dans [a_few_words].

Je sens que je suis proche, mais je manque juste un morceau de connaissances qui débloquera la clé pour faire ce travail chose un nombre infini de fois dans les limites de la première série de [] s contenu dans une ligne ( de SQL Server dans DDL ce cas).

Toutes les suggestions reçues avec reconnaissance ....

Était-ce utile?

La solution

Il y a deux parties à la supercherie nécessaire:

  1. Arrêter le remplacement lorsque vous atteignez un support carré près (mais faites à plusieurs reprises sur la ligne):

    s/\(\[[^] ]*\) /\1_/g
    

    correspond à un carré ouvert support, suivi par zéro ou plusieurs caractères qui ne sont ni un blanc, ni un support carré près. Les moyens de suffixe globaux que le motif est appliqué à toutes les séquences commençant par un crochet ouvert suivi éventuellement par un support vierge ou carré à proximité de la ligne. Notez aussi que cette regex ne modifie « [single-word] and context » alors que l'original se traduirait que de « [single-word]_and context », ce qui est l'objet de l'exercice.

  2. Get sed pour répéter la recherche de l'endroit où celui-ci a commencé. Malheureusement, il n'y a pas vraiment une bonne façon de le faire. Sed reprend toujours à la recherche après le texte qui a été remplacé; et c'est une occasion où nous ne voulons pas. Parfois, vous pouvez vous contenter de simplement répéter l'opération de substitution. Dans ce cas, vous devez répéter chaque fois que la substitution réussit, l'arrêt quand il n'y a plus de substitutions.

Deux des opérations moins bien connues dans sed sont les « :label » et les commandes « de t ». Ils étaient présents dans la 7ème édition d'Unix (vers 1978), cependant, ils ne sont pas de nouvelles fonctionnalités. Le premier identifie simplement une position dans le script qui peut sauter aux « b » (pas voulu ici) ou « t »:

[2addr]t [label]
     

Direction générale de la fonction « : » portant l'étiquette si des substitutions ont été effectuées depuis la plus récente lecture d'une ligne d'entrée ou de l'exécution d'une fonction «t. Si aucune étiquette est spécifiée, branche à la fin du script.

Marvelous: nous avons besoin:

 sed -e ':redo; s/\(\[[^] ]*\) /\1_/g; t redo' data.file

Sauf - il ne fonctionne pas sur une seule ligne comme ça (au moins, pas sur Mac OS X). Cela fait un travail admirable, bien que:

sed -e ':redo
        s/\(\[[^] ]*\) /\1_/g
        t redo' data.file

Ou, comme il est indiqué dans les commentaires, vous pouvez écrire trois options « -e » séparées (qui fonctionne sur Mac OS X):

 sed -e ':redo' -e 's/\(\[[^] ]*\) /\1_/g' -e 't redo' data.file

Compte tenu du fichier de données:

a line with [one blank] word inside square brackets.
a line with [two blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple words in a single bracket] inside square brackets.
a line with [multiple words in a single bracket] [several times on one line]

la sortie du script sed montré est:

a line with [one_blank] word inside square brackets.
a line with [two_blank] or [three_blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several_times_on_one_line]

Et, enfin, lire les petits caractères dans la question, si vous avez besoin de ce fait que dans le premier champ entre crochets sur chaque ligne, nous devons nous assurer que n'y a pas de crochets ouverts avant celui qui commence le match . Cette variante fonctionne:

sed -e ':redo' -e 's/^\([^]]*\[[^] ]*\) /\1_/' -e 't redo' data.file

(Le « g » qualificatif est allé - il est probablement pas nécessaire dans les autres variantes, soit compte tenu de la boucle;. Sa présence pourrait rendre légèrement plus efficace le processus, mais il serait très probablement presque impossibles à détecter que la motif est maintenant ancré au début de la ligne (le curseur) et contient zéro ou plusieurs caractères qui ne sont pas ouverts crochet avant que le premier crochet ouvert.)

Exemple de sortie:

a line with [two_blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several times on one line]

Autres conseils

Il est plus facile dans un langage comme Perl qui a substitutions "exécutables":

perl -wne 's/(\[.*?])/ do { my $x = $1; $x =~ y, ,_,; $x } /ge; print'

Ou pour le séparer plus clairement:

sub replace_with_underscores {
    my $s = shift;
    $s =~ y/ /_/;
    $s
}
s/(\[.*?])/ replace_with_underscores($1) /ge;

Le .*? est le match non gourmand (pour éviter empâtement ensemble deux phrases entre crochets adjacents) et le drapeau de e à la substitution, il provoque à évaluer, de sorte que vous pouvez appeler une fonction pour faire le travail intérieur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top