Je voudrais utiliser la méthode. Net Regex.Split pour scinder cette chaîne d'entrée en un tableau. Il doit diviser sur des espaces sauf s'il est entouré d'un devis.
Entrée: Voici "ma chaîne" il a "six correspondances"
Production attendue:
De quel motif ai-je besoin? De plus, dois-je spécifier des options Regex?
Aucune option requise
Regex:
\w+|"[\w\s]*"
C #:
Regex regex = new Regex(@"\w+|""[\w\s]*""");
Ou si vous devez exclure des "caractères:
Regex
.Matches(input, @"(?<match>\w+)|\""(?<match>[\w\s]*)""")
.Cast<Match>()
.Select(m => m.Groups["match"].Value)
.ToList()
.ForEach(s => Console.WriteLine(s));
La solution de Lieven fait l’objet d’une grande partie du chemin et, comme il le dit dans ses commentaires, il s’agit simplement 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 correspondances"
Sortie:
Malheureusement, cela inclut les citations. Si vous utilisez plutôt les éléments suivants:
(("((?<token>.*?)(?<!\\)")|(?<token>[\w]+))(\s)*)
Et capturez explicitement le "jeton" correspond 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 ] ) );
}
Sortie de débogage:
Token[0]: 'Here'
Token[1]: 'is'
Token[2]: 'my string'
Token[3]: 'it'
Token[4]: 'has'
Token[5]: ' six matches'
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;
}
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));
J'ai trouvé la regex dans cette réponse être très utile. Pour que cela fonctionne en C #, vous devrez utiliser la classe 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();
Cette expression rationnelle sera divisée en fonction du cas que vous avez donné ci-dessus, bien qu'elle ne supprime pas les guillemets ni les espaces supplémentaires. Vous souhaiterez donc peut-être effectuer un post-traitement sur vos chaînes. Cela devrait cependant maintenir correctement les chaînes entre guillemets.
"[^"]+"|\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 sautés (\ "), vous rencontrez un réel problème pour produire ou comprendre une expression régulière qui gérera cela correctement .
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, @"(?<match>[^""\s]+)|\""(?<match>[^""]*)""");
foreach (Match match in matchCollection)
{
yield return match.Groups["match"].Value;
}
vous pouvez rendre le foreach plus intelligent si vous utilisez .Net> 2.0
Shaun,
Je crois que la regex suivante devrait le faire
(?<=")\w[\w\s]*(?=")|\w+
Cordialement,
Lieven
Si vous souhaitez jeter un œil à une solution générale à ce problème sous la forme d'un objet javascript gratuit et à code source ouvert, vous pouvez visiter http://splitterjsobj.sourceforge.net/ pour une démonstration en direct. (et télécharger). L'objet a les caractéristiques suivantes:
L'objet est également disponible en tant que plug-in jQuery, mais en tant que nouvel utilisateur de ce site, je ne peux inclure qu'un seul lien dans ce message.
Jetez un coup d’œil à la fonction " Split de LSteinle qui prend en charge les qualificateurs de texte " dans le projet Code
Voici l'extrait de son projet qui vous intéresse.
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);
}
Veillez simplement à appeler ceci dans une boucle lors de la création et de la compilation de 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 créerais un cache Regex.