67 votes

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

Je voudrais utiliser la méthode. Net Regex.Split pour scinder cette chaîne d'entrée en un tableau. Il doit être divisé sur des espaces, sauf s'il est placé entre guillemets.

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

Production attendue:

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

De quel motif ai-je besoin? De plus, dois-je spécifier des options Regex?

63voto

Bartek Szabat Points 1611

Aucune option requise

Regex:

 \w+|"[\w\s]*"
 

C #:

 Regex regex = new Regex(@"\w+|""[\w\s]*""");
 

Ou si vous avez besoin d'exclure des "personnages:

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

16voto

Timothy Walters Points 8222

Lieven de la solution en prend le chemin, et tel qu'il l'expose dans ses commentaires, c'est juste une question de changer la fin de Bartek de la solution. Le résultat final est le suivant travail regEx:

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

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

Sortie:

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

Malheureusement, c'est entre guillemets. Si vous utilisez plutôt la commande suivante:

(("((?<token>.*?)(?<!\\)")|(?<token>[\w]+))(\s)*)

Et explicitement, de capturer le "jeton" des matchs comme suit:

    RegexOptions options = RegexOptions.None;
    Regex regex = new Regex( @"((""((?<token>.*?)(?<!\\)"")|(?<token>[\w]+))(\s)*)", options );
    string input = @"   Here is ""my string"" 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 ] ) );
    }

La sortie de débogage:

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

9voto

Richard Shepherd Points 464

La meilleure réponse ne fonctionne pas vraiment pour moi. J'essayais de diviser ce type de chaîne par des espaces, mais il semblerait que les points ('.') Se divisent également.

 "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 le faire:

     /// <summary>
    /// Splits the string passed in by the delimiters passed in.
    /// Quoted sections are not split, and all tokens have whitespace
    /// trimmed from the start and end.
    public static List<string> split(string stringToSplit, params char[] delimiters)
    {
        List<string> results = new List<string>();

        bool inQuote = false;
        StringBuilder currentToken = new StringBuilder();
        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;
    }
 

7voto

Boinst Points 825

J'utilisais la réponse de Bartek Szabat, mais je devais capturer plus que des "\ w" caractères dans mes jetons. Pour résoudre le problème, j'ai légèrement modifié sa regex, semblable à la réponse de Grzenio:

 Regular Expression: (?<match>[^\s"]+)|(?<match>"[^"]*")

C# String:          (?<match>[^\\s\"]+)|(?<match>\"[^\"]*\")
 

Le code de Bartek (qui renvoie des jetons dépourvus de guillemets) devient:

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

4voto

John Conrad Points 144

Cette expression rationnelle sera scindée en fonction de la casse que vous avez donnée ci-dessus, bien qu'elle ne supprime pas les guillemets ni les espaces supplémentaires. Par conséquent, vous souhaiterez peut-être effectuer un post-traitement sur vos chaînes. Cela devrait cependant maintenir correctement les chaînes entre guillemets.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X