Expression régulière à diviser sur des espaces sauf entre guillemets

Je voudrais utiliser la méthode .Net Regex.Split pour diviser cette chaîne d’entrée en un tableau. Il doit être divisé sur des espaces, sauf s’il est inclus dans une citation.

Entrée: Voici “ma chaîne” il a “six matchs”

Production attendue:

  1. Ici
  2. est
  3. ma ficelle
  4. il
  5. a
  6. six matchs

De quel modèle ai-je besoin? Dois-je également spécifier des RegexOptions?

La solution de Lieven est là pour l’essentiel et, comme il le dit dans ses commentaires, il suffit de changer la fin en solution de Bartek. Le résultat final est le regEx de travail suivant:

 (?<=")\w[\w\s]*(?=")|\w+|"[\w\s]*" 

Entrée: Voici "ma chaîne" il a "six matchs"

Sortie:

  1. Ici
  2. est
  3. "ma chaîne"
  4. il
  5. a
  6. "six matchs"

Malheureusement, il comprend les citations. Si vous utilisez plutôt ce qui suit:

 (("((?.*?)(?[\w]+))(\s)*) 

Et capturer explicitement les correspondances "jeton" comme suit:

  RegexOptions options = RegexOptions.None; Regex regex = new Regex( @"((""((?.*?)(?[\w]+))(\s)*)", options ); ssortingng input = @" Here is ""my ssortingng"" it has "" six matches"" "; var result = (from Match m in regex.Matches( input ) where m.Groups[ "token" ].Success select m.Groups[ "token" ].Value).ToList(); for ( int i = 0; i < result.Count(); i++ ) { Debug.WriteLine( string.Format( "Token[{0}]: '{1}'", i, result[ i ] ) ); } 

Sortie de débogage:

 Token[0]: 'Here' Token[1]: 'is' Token[2]: 'my ssortingng' Token[3]: 'it' Token[4]: 'has' Token[5]: ' six matches' 

J’utilisais la réponse de Bartek Szabat, mais j’avais besoin de capturer plus que des caractères “\ w” dans mes jetons. Pour résoudre le problème, j’ai légèrement modifié sa regex, comme la réponse de Grzenio:

 Regular Expression: (?[^\s"]+)|(?"[^"]*") C# Ssortingng: (?[^\\s\"]+)|(?\"[^\"]*\") 

Le code de Bartek (qui renvoie les jetons dépouillés de guillemets) devient:

 Regex .Matches(input, "(?[^\\s\"]+)|(?\"[^\"]*\")") .Cast() .Select(m => m.Groups["match"].Value) .ToList() .ForEach(s => Console.WriteLine(s)); 

La meilleure réponse ne fonctionne pas vraiment pour moi. J’essayais de diviser ce type de chaîne par des espaces, mais il semble que cela se divise également sur les points (‘.’).

 "the lib.lib" "another lib".lib 

Je sais que la question concerne les regex, mais j’ai fini par écrire une fonction non-regex pour faire ceci:

  ///  /// Splits the ssortingng passed in by the delimiters passed in. /// Quoted sections are not split, and all tokens have whitespace /// sortingmmed from the start and end. public static List split(ssortingng ssortingngToSplit, params char[] delimiters) { List results = new List(); bool inQuote = false; SsortingngBuilder currentToken = new SsortingngBuilder(); for (int index = 0; index < stringToSplit.Length; ++index) { char currentCharacter = stringToSplit[index]; if (currentCharacter == '"') { // When we see a ", we need to decide whether we are // at the start or send of a quoted section... inQuote = !inQuote; } else if (delimiters.Contains(currentCharacter) && inQuote == false) { // We've come to the end of a token, so we find the token, // trim it and add it to the collection of results... string result = currentToken.ToString().Trim(); if (result != "") results.Add(result); // We start a new token... currentToken = new StringBuilder(); } else { // We've got a 'normal' character, so we add it to // the curent token... currentToken.Append(currentCharacter); } } // We've come to the end of the string, so we add the last token... string lastResult = currentToken.ToString().Trim(); if (lastResult != "") results.Add(lastResult); return results; } 

J’ai trouvé la regex dans cette réponse très utile. Pour le faire fonctionner en C #, vous devrez utiliser la classe MatchCollection.

 //need to escape \s ssortingng pattern = "[^\\s\"']+|\"([^\"]*)\"|'([^']*)'"; MatchCollection parsedSsortingngs = Regex.Matches(line, pattern); for (int i = 0; i < parsedStrings.Count; i++) { //print parsed strings Console.Write(parsedStrings[i].Value + " "); } Console.WriteLine(); 

Cette regex sera divisée en fonction du cas que vous avez donné ci-dessus, même si elle ne supprime pas les guillemets ni les espaces supplémentaires. Vous pouvez donc effectuer un post-traitement sur vos chaînes. Cela devrait garder correctement les chaînes entre elles.

 "[^"]+"|\s?\w+?\s 

Avec un peu de désordre, les langages normaux peuvent garder une trace du comptage pair / impair des guillemets, mais si vos données peuvent inclure des guillemets échappés (\ “), alors vous avez vraiment du mal à produire ou à comprendre une expression régulière. .

Shaun,

Je crois que la regex suivante devrait le faire

 (?<=")\w[\w\s]*(?=")|\w+ 

Cordialement,
Lieven

EDIT: Désolé pour mon post précédent, c’est évidemment possible.

Pour gérer tous les caractères non alphanumériques, vous avez besoin de quelque chose comme ceci:

 MatchCollection matchCollection = Regex.Matches(input, @"(?[^""\s]+)|\""(?[^""]*)"""); foreach (Match match in matchCollection) { yield return match.Groups["match"].Value; } 

vous pouvez rendre le foreach plus intelligent si vous utilisez .Net> 2.0

Jetez un coup d’oeil à la ” fonction fractionnée qui prend en charge les qualificateurs de texte ” de LSteinle sur le projet at Code

Voici l’extrait de son projet qui vous intéresse.

 using System.Text.RegularExpressions; public ssortingng[] Split(ssortingng expression, ssortingng delimiter, ssortingng qualifier, bool ignoreCase) { ssortingng _Statement = Ssortingng.Format("{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))", Regex.Escape(delimiter), Regex.Escape(qualifier)); RegexOptions _Options = RegexOptions.Comstackd | RegexOptions.Multiline; if (ignoreCase) _Options = _Options | RegexOptions.IgnoreCase; Regex _Expression = New Regex(_Statement, _Options); return _Expression.Split(expression); } 

Il suffit de faire attention à l’appel en boucle pour créer et comstackr l’instruction Regex chaque fois que vous l’appelez. Donc, si vous avez besoin de l’appeler plus d’une poignée de fois, je chercherais à créer un cache Regex quelconque.

Si vous souhaitez examiner une solution générale à ce problème sous la forme d’un object javascript gratuit et open-source, vous pouvez visiter http://splitterjsobj.sourceforge.net/ pour une démonstration en direct (et le télécharger). . L’object a les fonctionnalités suivantes:

  • Les paires de caractères de citation définis par l’utilisateur peuvent être utilisées pour échapper au délimiteur (éviter un fractionnement entre guillemets). Les guillemets peuvent être échappés avec un caractère d’échappement défini par l’utilisateur et / ou par “double quote escape”. Le caractère d’échappement peut être échappé (avec lui-même). Dans l’un des 5 tableaux de sortie (propriétés de l’object), la sortie n’est pas échapée. (Par exemple, si le caractère d’échappement = /, “a ///” b “n’est pas échappé en tant que /” b)
  • Diviser sur un tableau de délimiteurs; parsingr un fichier en un seul appel. (Les tableaux de sortie seront nesteds.)
  • Toutes les séquences d’échappement reconnues par JavaScript peuvent être évaluées pendant le processus de fractionnement et / ou dans un pré-traitement.
  • Fonctionnalité de rappel
  • Cohérence entre les navigateurs

L’object est également disponible en tant que plug-in jQuery, mais en tant que nouvel utilisateur sur ce site, je ne peux inclure qu’un seul lien dans ce message.