Question

J'ai de la chaîne comme ceci

 /c SomeText\MoreText "Some Text\More Text\Lol" SomeText

Je veux marquer, cependant je ne peux pas juste se diviser sur les espaces.Je suis venu avec un peu laid analyseur qui fonctionne, mais je me demandais si quelqu'un a un plus d'un design élégant.

C'est en C# btw.

EDIT: Ma version laide, tout moche, est O(N) et peut en fait être plus rapide que l'utilisation d'une expression régulière.

private string[] tokenize(string input)
{
    string[] tokens = input.Split(' ');
    List<String> output = new List<String>();

    for (int i = 0; i < tokens.Length; i++)
    {
        if (tokens[i].StartsWith("\""))
        {
            string temp = tokens[i];
            int k = 0;
            for (k = i + 1; k < tokens.Length; k++)
            {
                if (tokens[k].EndsWith("\""))
                {
                    temp += " " + tokens[k];
                    break;
                }
                else
                {
                    temp += " " + tokens[k];
                }
            }
            output.Add(temp);
            i = k + 1;
        }
        else
        {
            output.Add(tokens[i]);
        }
    }

    return output.ToArray();            
}
Était-ce utile?

La solution

L'ordinateur terme pour ce que vous faites est l'analyse lexicale;lire que pour un bon résumé de cette tâche commune.

Basé sur votre exemple, je suppose que vous voulez des espaces pour séparer vos mots, mais des trucs entre guillemets doit être traité comme un "mot", sans les guillemets.

La façon la plus simple de le faire est de définir un mot comme une expression régulière:

([^"^\s]+)\s*|"([^"]+)"\s*

Cette expression indique qu'un "mot" est soit (1) la non-citation, non-blanc texte entouré par des espaces, ou (2) la non-citation du texte entouré par des guillemets (suivi de certains espaces).Notez l'utilisation de la capture des parenthèses pour mettre en surbrillance le texte de votre choix.

Armé avec cette regex, votre algorithme est simple:rechercher votre texte pour le prochain "mot" comme défini par la parenthèse capturante, et de le retourner.Répétez jusqu'à ce que vous exécutez hors de "mots".

Voici la plus simple de bits du code du travail que je pouvais venir, dans VB.NET.Notez que nous avons à vérifier les deux les groupes de données puisqu'il y a deux ensembles de parenthèse capturante.

Dim token As String
Dim r As Regex = New Regex("([^""^\s]+)\s*|""([^""]+)""\s*")
Dim m As Match = r.Match("this is a ""test string""")

While m.Success
    token = m.Groups(1).ToString
    If token.length = 0 And m.Groups.Count > 1 Then
        token = m.Groups(2).ToString
    End If
    m = m.NextMatch
End While

Note 1: Will réponse ci-dessus est la même idée que celle-ci.J'espère que cette réponse explique les détails derrière la scène, un peu mieux :)

Autres conseils

La Microsoft.VisualBasic.FileIO espace de noms (dans Microsoft.VisualBasic.dll) a un TextFieldParser vous pouvez utiliser pour diviser l'espace delimeted texte.Il gère les chaînes entre guillemets (c'est à dire, "c'est un jeton" thisistokentwo) bien.

Note, tout simplement parce que la DLL dit VisualBasic ne signifie pas que vous ne pouvez l'utiliser que dans un projet VB.Sa partie de l'ensemble du Cadre.

Il y a la machine de l'etat de l'approche.

    private enum State
    {
        None = 0,
        InTokin,
        InQuote
    }

    private static IEnumerable<string> Tokinize(string input)
    {
        input += ' '; // ensure we end on whitespace
        State state = State.None;
        State? next = null; // setting the next state implies that we have found a tokin
        StringBuilder sb = new StringBuilder();
        foreach (char c in input)
        {
            switch (state)
            {
                default:
                case State.None:
                    if (char.IsWhiteSpace(c))
                        continue;
                    else if (c == '"')
                    {
                        state = State.InQuote;
                        continue;
                    }
                    else
                        state = State.InTokin;
                    break;
                case State.InTokin:
                    if (char.IsWhiteSpace(c))
                        next = State.None;
                    else if (c == '"')
                        next = State.InQuote;
                    break;
                case State.InQuote:
                    if (c == '"')
                        next = State.None;
                    break;
            }
            if (next.HasValue)
            {
                yield return sb.ToString();
                sb = new StringBuilder();
                state = next.Value;
                next = null;
            }
            else
                sb.Append(c);
        }
    }

Il peut facilement être étendu pour des choses imbriquées comme des citations et de s'évader.De retour en tant que IEnumerable<string> permet à votre code à analyser uniquement les fichiers comme vous le souhaitez.Il n'y a pas de véritables inconvénients de ce genre de paresseux approche des chaînes de caractères sont immuables, de sorte que vous savez que input ne changera pas avant de vous avoir analysé l'ensemble de la chose.

Voir: http://en.wikipedia.org/wiki/Automata-Based_Programming

Vous pouvez également regarder dans les expressions régulières.Qui pourrait vous aider.Voici un exemple arraché à partir de MSDN...

using System;
using System.Text.RegularExpressions;

public class Test
{

    public static void Main ()
    {

        // Define a regular expression for repeated words.
        Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",
          RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Define a test string.        
        string text = "The the quick brown fox  fox jumped over the lazy dog dog.";

        // Find matches.
        MatchCollection matches = rx.Matches(text);

        // Report the number of matches found.
        Console.WriteLine("{0} matches found in:\n   {1}", 
                          matches.Count, 
                          text);

        // Report on each match.
        foreach (Match match in matches)
        {
            GroupCollection groups = match.Groups;
            Console.WriteLine("'{0}' repeated at positions {1} and {2}",  
                              groups["word"].Value, 
                              groups[0].Index, 
                              groups[1].Index);
        }

    }

}
// The example produces the following output to the console:
//       3 matches found in:
//          The the quick brown fox  fox jumped over the lazy dog dog.
//       'The' repeated at positions 0 and 4
//       'fox' repeated at positions 20 and 25
//       'dog' repeated at positions 50 and 54

Craig droit d'utiliser des expressions régulières. Regex.Split peut-être plus concis pour vos besoins.

[^ ]+ |"[^"]+"

en utilisant les Regex certainement ressemble le meilleur pari, mais celui-ci retourne l'ensemble de la chaîne.Je suis en train de le modifier, mais pas beaucoup de chance jusqu'à présent.

string[] tokens = System.Text.RegularExpressions.Regex.Split(this.BuildArgs, @"[^\t]+\t|""[^""]+""\t");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top