2016-10-26 1 views
2

J'ai entrée qui a des champsremplacer les espaces différemment à l'extérieur ou à l'intérieur des guillemets simples

  • séparés par des espaces,
  • d'autres sont entre guillemets et aussi séparés par des espaces

Voici un exemple d'entrée:

active=1 'oldest active'=0s disabled=0 'function call'=0 

Je voudrais remplacer:

  • tous les espaces citations en dehors de | et
  • toutes les citations à l'intérieur de _

sortie seraient:

active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

J'ai essayé différentes solutions avec sed ou perl trouvé sur le web mais je n'ai pas réussi à faire ce que je veux.

Répondre

2
$ s="active=1 'oldest active'=0s disabled=0 'function call'=0" 
$ echo "$s" | perl -pe "s/'[^']*'(*SKIP)(*F)| /|/g; s/ /_/g" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

Deux remplacement étapes:

  • D'abord, '[^']*'(*SKIP)(*F) ignorera tous les modèles entourés de ' et de remplacer les espaces restants avec |
  • En second lieu, les espaces maintenant laissés à l'intérieur ' sera remplacé par _


Autre solution:

$ echo "$s" | perl -pe "s/'[^']*'/$& =~ s| |_|gr/ge; s/ /|/g" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 
  • inspiré de this answer
  • '[^']*'/$& =~ s| |_|gr/ge remplacer tous les espaces motif correspondant '[^']*' en utilisant une autre commande de remplacement. Le modificateur e permet d'utiliser la commande au lieu de chaîne dans la section de remplacement
  • les espaces restants sont ensuite pris en charge avec s/ /|/g


Pour en savoir plus:

+0

Wow, quelle réponse rapide et efficace! Merci pour l'explication aussi. Y at-il une bonne documentation de tous les paramètres disponibles (comme SKIP, ...)? – BDR

+0

voir http://www.rexegg.com/backtracking-control-verbs.html et http://www.rexegg.com/regex-best-trick.html – Sundeep

0

Nous pouvons utiliser l'expression régulière à l'intérieur de la boucle.

$str = "active=1 'oldest active'=0s disabled=0 'function call'=0"; 
print "\nBEF: $str\n"; 
$str =~s#active=1 'oldest active'=0s disabled=0 'function call'=0# my $tmp=$&; $tmp=~s/\'([^\']*)\'/my $tes=$&; $tes=~s{ }{\_}g; ($tes)/ge; $tmp=~s/ /\|/g; ($tmp); #ge; 
print "\nAFT: $str\n"; 

Peut-être quelques chemins courts seront là en dehors de cela.

1

En utilisant gnu awk FPAT, vous pouvez le faire:

s="active=1 'oldest active'=0s disabled=0 'function call'=0" 

awk -v OFS="|" -v FPAT="'[^']*'[^[:blank:]]*|[^[:blank:]]+" '{ 
    for (i=1; i<=NF; i++) gsub(/[[:blank:]]/, "_", $i)} 1' <<< "$s" 

active=1|'oldest_active'=0s|disabled=0|'function_call'=0 
  • En FPAT regex, nous utilisons l'alternance pour créer des champs de toutes les valeurs entre guillemets simples + valeur non-espace-à-dire '[^']*'[^[:blank:]]* ou des valeurs non-blancs c'est-à-dire [^[:blank:]]+ depuis l'entrée.
  • En utilisant gsub, nous remplaçons simplement tous les espaces par _ car nous n'obtiendrons que des espaces entre guillemets simples dans tous les champs.
  • Enfin en utilisant OFS='|' nous délimitons sortie avec |

Référence:Effective AWK Programming

+1

Bonne capture @Sundeep. C'est réparé maintenant. – anubhava

1

Cela pourrait fonctionner pour vous (GNU sed):

sed -r ":a;s/^([^']*('[^ ']*')*[^']*'[^' ]*) /\1_/;ta;y/ /|/" file 

Ce premier remplace tous les espaces à coté chaînes par _, puis traduit les espaces restants à |.

1

@ solution de anubhava appelle à l'esprit une solution perl old-school:

$ echo $s | perl -047 -pe "(\$.%2)?s/ /|/g:s/ /_/g;" 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0 

diviser les lignes par des guillemets simples (047) et sous basé sur pair/impair.

+0

pas besoin d'utiliser des guillemets doubles ... 'perl -047 -pe '($.% 2)? S// |/g: s// _/g;'' – Sundeep

+0

vrai. signe d'un bash amateur. – albe

0
$ awk -F\' '{OFS=FS; for (i=1;i<=NF;i++) gsub(/ /,(i%2?"|":"_"),$i)}1' file 
active=1|'oldest_active'=0s|disabled=0|'function_call'=0