Expresión regular para dividir en espacios a menos que entre comillas

Me gustaría utilizar el método .Net Regex.Split para dividir esta cadena de entrada en una matriz. Debe dividirse en espacios en blanco a menos que esté encerrado en una cita.

Entrada: Aquí está “mi cadena” tiene “seis coincidencias”

Rendimiento esperado:

  1. aquí
  2. es
  3. mi cadena
  4. eso
  5. tiene
  6. seis partidos

¿Qué patrón necesito? ¿También necesito especificar alguna RegexOptions?

No se requieren opciones

Regex:

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

DO#:

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

O si necesita excluir “caracteres”:

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

La solución de Lieven se lleva la mayor parte del camino, y como afirma en sus comentarios, solo se trata de cambiar el final a la solución de Bartek. El resultado final es el siguiente regEx de trabajo:

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

Entrada: Aquí está "mi cadena" tiene "seis coincidencias"

Salida:

  1. aquí
  2. es
  3. "mi cuerda"
  4. eso
  5. tiene
  6. "seis partidos"

Desafortunadamente está incluyendo las comillas. Si, en su lugar, usa lo siguiente:

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

Y capture explícitamente las coincidencias "token" de la siguiente manera:

  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 ] ) ); } 

Salida de depuración:

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

Estaba usando la respuesta de Bartek Szabat, pero necesitaba capturar más que solo “\ w” caracteres en mis tokens. Para resolver el problema, modifiqué su expresión regular ligeramente, de forma similar a la respuesta de Grzenio:

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

El código de Bartek (que devuelve tokens sin comillas) se convierte en:

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

La respuesta principal no funciona para mí. Estaba tratando de dividir este tipo de cadena por espacios, pero parece que se divide en los puntos (‘.’) También.

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

Sé que la pregunta me pregunta acerca de las expresiones regulares, pero terminé escribiendo una función no regex para hacer esto:

  ///  /// 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; } 

He encontrado que la expresión regular en esta respuesta es bastante útil. Para que funcione en C # tendrá que usar la clase 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(); 

Esta expresión regular se dividirá en función del caso que ha indicado anteriormente, aunque no elimina las comillas o los espacios adicionales, por lo que es posible que desee realizar un procesamiento posterior en sus cadenas. Sin embargo, esto debería mantener correctamente las cadenas entrecomilladas juntas.

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

Con un poco de desorden, los idiomas regulares pueden realizar un seguimiento del recuento par / impar de las comillas, pero si sus datos pueden incluir comillas escapadas (\ “), entonces tiene problemas para producir o comprender una expresión regular que manejará correctamente .

Shaun,

Creo que la siguiente expresión regular debería hacerlo

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

Saludos,
Lieven

EDITAR: Lo siento por mi publicación anterior, esto es obviamente posible.

Para manejar todos los caracteres no alfanuméricos necesita algo como esto:

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

puedes hacer el foreach más inteligente si estás usando .Net> 2.0

Eche un vistazo a la ” Función de división que admite calificadores de texto ” de LSteinle en el proyecto de código.

Aquí está el fragmento de su proyecto que le interesa.

 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); } 

Solo tenga cuidado con llamar esto en un bucle mientras crea y comstack la statement Regex cada vez que la llama. Entonces, si necesitas llamarlo más seguido un puñado de veces, consideraría crear un caché Regex de algún tipo.

Si desea ver una solución general a este problema en forma de un objeto javascript gratuito y de código abierto, puede visitar http://splitterjsobj.sourceforge.net/ para obtener una demostración en vivo (y descargar) . El objeto tiene las siguientes características:

  • Se pueden usar pares de caracteres de comillas definidos por el usuario para escapar del delimitador (evitar una división dentro de comillas). Las comillas se pueden escapar con un carácter de escape definido por el usuario y / o mediante “escape de doble cita”. El escape char se puede escapar (consigo mismo). En una de las 5 matrices de salida (propiedades del objeto), la salida no está protegida. (Por ejemplo, si el escape char = /, “a ///” b “no está protegido como a /” b)
  • Dividir en una matriz de delimitadores; analizar un archivo en una llamada. (Las matrices de salida estarán anidadas).
  • Todas las secuencias de escape reconocidas por javascript se pueden evaluar durante el proceso de división y / o en un preproceso.
  • Funcionalidad de callback
  • Consistencia entre navegadores

El objeto también está disponible como un complemento jQuery, pero como nuevo usuario en este sitio, solo puedo incluir un enlace en este mensaje.