Regex pour choisir des virgules en dehors des guillemets

Je ne suis pas tout à fait sûr si cela est possible, donc je me tourne vers vous.

Je voudrais trouver une expression rationnelle qui choisira toutes les virgules qui tombent en dehors des ensembles de citations.

Par exemple:

'foo' => 'bar',
'foofoo' => 'bar,bar'

Ce serait choisir la virgule sur la ligne 1, après 'bar',

Je ne me soucie pas vraiment des guillemets simples vs doubles.

Quelqu'un a-t-il des idées? Je pense que cela devrait être possible avec readaheads, mais mon regex fu est trop faible.

33
demandé sur TheCloudlessSky 2009-03-11 01:09:41

6 réponses

Cela correspondra à n'importe quelle chaîne jusqu'à et y compris le premier", "Non Cité. Est-ce que vous êtes désireux?

/^([^"]|"[^"]*")*?(,)/

Si vous voulez tous (et comme contre-exemple pour le gars qui a dit que ce n'était pas possible), vous pouvez écrire:

/(,)(?=(?:[^"]|"[^"]*")*$)/

Qui correspondra à tous. Ainsi

'test, a "comma,", bob, ",sam,",here'.gsub(/(,)(?=(?:[^"]|"[^"]*")*$)/,';')

Remplace toutes les virgules pas à l'intérieur de guillemets par des points-virgules, et produit:

'test; a "comma,"; bob; ",sam,";here'

Si vous en avez besoin pour fonctionner à travers les sauts de ligne, ajoutez simplement le drapeau m (multiligne).

78
répondu MarkusQ 2009-03-11 16:32:48

Les expressions rationnelles ci-dessous correspondraient à toutes les virgules présentes en dehors des guillemets doubles,

,(?=(?:[^"]*"[^"]*")*[^"]*$)

DÉMO

Ou (PCRE uniquement)

"[^"]*"(*SKIP)(*F)|,

"[^"]*" correspond à tous les blocs guillemets doubles. C'est-à-dire que dans cette entrée buz,"bar,foo", cette expression rationnelle ne correspondrait qu'à "bar,foo". Maintenant, le (*SKIP)(*F) suivant fait échouer la correspondance. Ensuite, il passe au motif qui était à côté du symbole | et essaie de faire correspondre les caractères de la chaîne restante. C'est, à notre sortie , à côté du motif {[7] } ne correspondra qu'à la virgule Qui était juste après buz . Notez que cela ne correspondra pas à la virgule Qui était présente à l'intérieur des guillemets doubles, car nous faisons déjà sauter la partie entre guillemets doubles.

DÉMO


La regex ci-dessous correspondrait à toutes les virgules qui sont présentes à l'intérieur des guillemets doubles,

,(?!(?:[^"]*"[^"]*")*[^"]*$)

DÉMO

7
répondu Avinash Raj 2015-03-16 13:15:36

Bien qu'il soit possible de le pirater avec une expression rationnelle (et j'aime abuser des expressions rationnelles autant que le gars suivant), vous aurez des problèmes tôt ou tard en essayant de gérer des sous-chaînes sans un analyseur plus avancé. Les moyens possibles d'avoir des ennuis incluent des citations mixtes et des citations échappées.

Cette fonction va diviser une chaîne sur des virgules, mais pas celles qui sont dans une chaîne entre guillemets simples ou doubles. Il peut être facilement étendu avec des caractères supplémentaires à utiliser comme guillemets (bien que le caractère des paires comme "" auraient besoin de quelques lignes de code supplémentaires) et vous diront même si vous avez oublié de fermer un devis dans vos données:

function splitNotStrings(str){
  var parse=[], inString=false, escape=0, end=0

  for(var i=0, c; c=str[i]; i++){ // looping over the characters in str
    if(c==='\\'){ escape^=1; continue} // 1 when odd number of consecutive \
    if(c===','){
      if(!inString){
        parse.push(str.slice(end, i))
        end=i+1
      }
    }
    else if(splitNotStrings.quotes.indexOf(c)>-1 && !escape){
      if(c===inString) inString=false
      else if(!inString) inString=c
    }
    escape=0
  }
  // now we finished parsing, strings should be closed
  if(inString) throw SyntaxError('expected matching '+inString)
  if(end<i) parse.push(str.slice(end, i))
  return parse
}

splitNotStrings.quotes="'\"" // add other (symmetrical) quotes here
2
répondu Touffy 2015-04-05 19:11:44

Essayez cette expression régulière:

(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*=>\s*(?:"(?:[^\\"]+|\\(?:\\\\)*[\\"])*"|'(?:[^\\']+|\\(?:\\\\)*[\\'])*')\s*,

Cela permet également des chaînes comme " 'foo\'bar' => 'bar\\',".

1
répondu Gumbo 2009-03-10 22:45:29

La réponse de MarkusQ a très bien fonctionné pour moi pendant environ un an, jusqu'à ce que ce ne soit pas le cas.je viens de recevoir une erreur de débordement de pile sur une ligne avec environ 120 virgules et 3682 caractères au total. En Java, comme ceci:

        String[] cells = line.split("[\t,](?=(?:[^\"]|\"[^\"]*\")*$)", -1);

Voici mon remplacement extrêmement inélégant qui n'empile pas le débordement:

private String[] extractCellsFromLine(String line) {
    List<String> cellList = new ArrayList<String>();
    while (true) {
        String[] firstCellAndRest;
        if (line.startsWith("\"")) {
            firstCellAndRest = line.split("([\t,])(?=(?:[^\"]|\"[^\"]*\")*$)", 2);
        }
        else {
            firstCellAndRest = line.split("[\t,]", 2);                
        }
        cellList.add(firstCellAndRest[0]);
        if (firstCellAndRest.length == 1) {
            break;
        }
        line = firstCellAndRest[1];
    }
    return cellList.toArray(new String[cellList.size()]);
}
1
répondu sullivan- 2011-05-10 01:54:08

@ SocialCensus, l'exemple que vous avez donné dans le commentaire à MarkusQ, où vous jetez ' à côté du ", ne fonctionne pas avec L'exemple que MarkusQ a donné juste au-dessus que si nous changeons sam à sam : (test, a "comma,", bob, ",sam's,",ici) n'a pas de match contre (,)(?=(?:[^"']|["|'][^"']")$). En fait, le problème lui-même, "Je ne me soucie pas vraiment des guillemets simples vs doubles", est ambigu. Vous devez être clair ce que vous voulez dire en citant soit avec "ou avec". Exemple, est de nidification autorisé ou pas? Si oui, à combien de niveaux? Si seulement 1 niveau imbriqué, qu'arrive-t-il à une virgule en dehors de la citation imbriquée interne mais à l'intérieur de la citation d'imbrication externe? Vous devriez également considérer que les guillemets simples se produisent par eux-mêmes en tant qu'apostrophes (c'est-à-dire, comme le contre-exemple que j'ai donné plus tôt avec sam). Enfin, l'expression rationnelle que vous avez créée ne traite pas vraiment les guillemets simples à égalité avec les guillemets doubles, car elle suppose que le dernier type de guillemet est nécessairement un guillemet double - et remplacer cette dernière citation double par ['|"] a également un problème si le texte ne vient pas avec des guillemets corrects (ou si des apostrophes sont utilisées), cependant, je suppose que nous pourrions probablement supposer que toutes les citations sont correctement délimitées.

L'expression rationnelle de MarkusQ répond à la question: Trouvez toutes les virgules qui ont un nombre pair de guillemets doubles après (c'est-à-dire, sont en dehors des guillemets doubles) et ignorez toutes les virgules qui ont un nombre impair de guillemets doubles après (c'est-à-dire, sont à l'intérieur des guillemets doubles). C'est généralement le même solution que ce que vous voulez probablement, mais regardons quelques anomalies. Tout d'abord, si quelqu'un laisse un guillemet à la fin, alors cette expression rationnelle trouve toutes les fausses virgules plutôt que de trouver celles souhaitées ou de ne pas en correspondre. Bien sûr, si une citation double est manquante, tous les paris sont désactivés car il pourrait ne pas être clair si le manquant appartient à la fin ou à la place appartient au début; cependant, il y a un cas qui est légitime et où l'expression rationnelle pourrait éventuellement échouer (c'est le deuxième "anomalie"). Si vous ajustez l'expression rationnelle pour traverser les lignes de texte, vous devez savoir que citer plusieurs paragraphes consécutifs nécessite de placer un seul guillemet double au début de chaque paragraphe et de laisser le guillemet à la fin de chaque paragraphe, sauf à la fin du dernier paragraphe. Cela signifie que dans l'espace de ces paragraphes, l'expression rationnelle échouera à certains endroits et réussira à d'autres.

Exemples et brèves discussions du paragraphe les guillemets et les guillemets imbriqués peuvent être trouvés ici http://en.wikipedia.org/wiki/Quotation_mark .

1
répondu Jose_X 2011-05-10 11:43:56