Espressione regolare da dividere in spazi a meno che non siano tra virgolette

Vorrei usare il metodo .Net Regex.Split per suddividere questa stringa di input in una matrice. Deve dividere in spazi vuoti a meno che non sia racchiuso in una citazione.

Input: Ecco “la mia stringa” ha “sei partite”

Uscita prevista:

  1. Qui
  2. è
  3. la mia corda
  4. esso
  5. ha
  6. sei partite

Che modello ho bisogno? Devo anche specificare qualsiasi RegexOptions?

Nessuna opzione richiesta

regex:

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

C #:

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

O se hai bisogno di escludere “caratteri:

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

La soluzione di Lieven arriva per la maggior parte del tempo e, come afferma nei suoi commenti, è solo questione di cambiare il finale con la soluzione di Bartek. Il risultato finale è il seguente regEx di lavoro:

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

Input: Ecco "la mia stringa" ha "sei partite"

Produzione:

  1. Qui
  2. è
  3. "la mia stringa"
  4. esso
  5. ha
  6. "sei partite"

Sfortunatamente include le virgolette. Se invece usi il seguente:

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

E catturare esplicitamente le corrispondenze "token" come segue:

  RegexOptions options = RegexOptions.None; Regex regex = new Regex( @"((""((?.*?)(?[\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 ] ) ); } 

Uscita di debug:

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

Stavo usando la risposta di Bartek Szabat, ma avevo bisogno di catturare più di “\ w” caratteri nei miei token. Per risolvere il problema, ho modificato leggermente il suo regex, simile alla risposta di Grzenio:

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

Il codice di Bartek (che restituisce i token svuotati delle virgolette) diventa:

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

La risposta migliore non funziona per me. Stavo cercando di dividere questo tipo di stringa per spazi, ma sembra che si divida anche sui punti (‘.’).

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

So che la domanda si interroga sulle regex, ma alla fine ho scritto una funzione non-regex per fare ciò:

  ///  /// 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 split(string stringToSplit, params char[] delimiters) { List results = new List(); 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; } 

Ho trovato la regex in questa risposta per essere abbastanza utile. Per farlo funzionare in C # dovrai usare la class MatchCollection.

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

Questa espressione regolare verrà suddivisa in base al caso che hai indicato sopra, sebbene non rimuova le virgolette o gli spazi aggiuntivi, quindi potresti voler eseguire alcune elaborazioni post sulle stringhe. Questo dovrebbe correttamente tenere insieme le stringhe insieme.

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

Con un po ‘di confusione, i linguaggi regolari possono tenere traccia del conteggio pari o dispari delle virgolette, ma se i tuoi dati possono includere virgolette di escape (\ “) allora sei nei guai nella produzione o nella comprensione di un’espressione regolare che gestirà correttamente .

Shaun

Credo che la seguente regex dovrebbe farlo

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

Saluti,
Lieven

EDIT: Ci scusiamo per il mio post precedente, questo è ovviamente ansible.

Per gestire tutti i caratteri non alfanumerici hai bisogno di qualcosa del genere:

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

puoi rendere il foreach più intelligente se stai usando .Net> 2.0

Dai un’occhiata alla ” Funzione Split che supporta i qualificatori di testo ” di LSteinle sul progetto Codice

Ecco lo snippet del suo progetto a cui sei interessato.

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

Fai attenzione a chiamare questo in un ciclo mentre crea e compila l’istruzione Regex ogni volta che lo chiami. Quindi, se hai bisogno di chiamarlo più di una volta, guarderei la creazione di una cache Regex di qualche tipo.

Se vuoi dare un’occhiata a una soluzione generale a questo problema sotto forma di un object javascript open source gratuito, puoi visitare http://splitterjsobj.sourceforge.net/ per una demo dal vivo (e scaricare) . L’object ha le seguenti caratteristiche:

  • È ansible utilizzare coppie di caratteri di virgoletta definiti dall’utente per sfuggire al delimitatore (evitare una divisione tra virgolette interne). Le virgolette possono essere sfuggite con un carattere di escape definito dall’utente e / o con “escape doppia citazione”. Il carattere di escape può essere sfuggito (con se stesso). In uno dei 5 array di output (proprietà dell’object), l’output non viene sottoposto a escape. (Ad esempio, se il carattere di escape = /, “a ///” b “non viene sostituito come a /” b)
  • Dividi su una matrice di delimitatori; analizzare un file in una sola chiamata. (Gli array di output saranno nidificati).
  • Tutte le sequenze di escape riconosciute da javascript possono essere valutate durante il processo di suddivisione e / o in pre-elaborazione.
  • Funzionalità di callback
  • Consistenza cross-browser

L’object è anche disponibile come plugin jQuery, ma come nuovo utente in questo sito posso includere solo un link in questo messaggio.