web-dev-qa-db-fra.com

Fractionner une chaîne (stockée dans une variable) en plusieurs mots en utilisant des espaces mais pas les espaces entre guillemets

J'essaie d'écrire un script compliqué pour moi dont le but est de faire ce qui suit. J'ai une ficelle qui ressemble à ceci:

2012 2013 "multiple words"

Mon objectif est de placer chacun de ceux-ci sur un tableau divisé en espaces, mais uniquement pour les correspondances Word simples, pas celles entourées de guillemets. Ceux-ci devraient être considérés comme un mot. Donc, mon idée était de faire cela en deux étapes. Commencez par faire correspondre les mots qui sont des multiples, supprimez ceux de la chaîne, puis dans une autre itération divisée par des espaces.
Malheureusement, je ne trouve aucune aide sur la façon de echo la correspondance uniquement. Jusqu'ici j'ai ceci:

array=$(echo $tags | sed -nE 's/"(.+)"/\1/p')

Mais cela se traduirait par (sous OS X):

2012 2013 multiple words

Résultat attendu:

array[1]="2012"
array[2]="2013"
array[3]="multiple words"

Comment pourrais-je résoudre ce type de problème? 

Merci.

19
Zettt

eval est diabolique, mais cela peut être l’un des cas où cela est utile

str='2012 2013 "multiple words"'
eval x=($str)
echo ${x[2]}
multiple words

Ou avec des versions plus récentes de bash (testé sur la version 4.3)

s='2012 2013 "multiple words"'
declare -a 'a=('"$s"')'
printf "%s\n" "${a[@]}"
2012
2013
multiple words
20
iruvar
$ grep -Eo '"[^"]*"|[^" ]*' <<< '2012 2013 "multiple words"'
2012
2013
"multiple words"

C'est-à-dire, print only les chaînes correspondantes

  1. une citation suivie d’un nombre (même zéro) de non-cotes suivi d’une citation ou
  2. une série de caractères ne contenant ni citation ni espace.

Bien sûr, cela not gère les cas compliqués tels que les guillemets couvrant plusieurs lignes ou les guillemets (en utilisant des guillemets doubles comme SQL ou une barre oblique inverse comme le shell).

4
l0b0

Vous pouvez directement faire:

arr=(2012 2013 "multiple words")

echo ${#arr[@]} # gives 3
echo ${arr[2]} # gives "multiple words"

EDIT: Je ne suis pas sûr que cela aide l'OP, mais cela fonctionnera également

str='2012 2013 "multiple\ words"'
read -a arr <<< $str
echo ${#arr[@]} # gives 3
echo ${arr[2]} # gives "multiple words"
2
anubhava

Ce qui suit produira le résultat souhaité:

tags='2012 2013 "multiple words"'
IFS=$'\n'; array=($(echo $tags | egrep -o '"[^"]*"|\S+'))

résultat en ZSH:

echo ${array[1]} # 2012
echo ${array[2]} # 2013
echo ${array[3]} # "multiple words"

résultat en BASH:

echo ${array[0]} # 2012
echo ${array[1]} # 2013
echo ${array[2]} # "multiple words"

fonctionne sous OSX.

1
zekus

Voici un petit script Python pour analyser les fichiers csv délimités par des espaces tout en respectant les champs cités:

$ python -c '
import csv, fileinput
for line in csv.reader(fileinput.input(), delimiter=" "):
   for Word in line:
      print Word
' test.csv
2012
2013
multiple words

Puisqu'il utilise le module fileinput, fonctionne dans un pipeline (ou une chaîne dans une variable):

$ str='2012 2013 "multiple words"'
$ echo $str | python -c '
import csv, fileinput
for line in csv.reader(fileinput.input(), delimiter=" "):
   for Word in line:
      print Word
' 
2012
2013
multiple words
0
dawg