سؤال

لدي سلسلة مثل هذا

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

أريد أن tokenize ، ومع ذلك لا أستطيع تقسيم المساحات.لقد جئت مع بعض الشيء القبيح محلل يعمل ولكن أنا أتساءل عما إذا كان أي شخص لديه تصميم أكثر أناقة.

هذا هو في C# راجع للشغل.

تحرير: قبيح الإصدار ، في حين القبيح ، O(N) و قد يكون في الواقع أسرع من استخدام التعابير المنطقية.

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();            
}
هل كانت مفيدة؟

المحلول

الكمبيوتر مصطلح ما تفعله هو تحليل المفردات;هذا ملخص جيد من هذه المهمة المشتركة.

على سبيل المثال, أعتقد أن كنت تريد فاصل لفصل الكلمات ، ولكن الاشياء في علامات اقتباس ينبغي أن تعامل على أنها "كلمة" بدون علامات الاقتباس.

أبسط طريقة للقيام بذلك هو تعريف كلمة العادية التعبير:

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

هذا التعبير على الدول التي "كلمة" هو إما (1) عدم الاقتباس غير فاصل النص وتحيط بها بيضاء أو (2) عدم اقتباس نص محاط ونقلت (تليها بعض بيضاء).لاحظ استخدام التقاط قوسين إلى تسليط الضوء على النص المطلوب.

المسلحة مع هذه التعابير المنطقية ، خوارزمية بسيطة:البحث النص الخاص بك المقبل "كلمة" على النحو المحدد في التقاط قوسين ، وإعادته.كرر ذلك حتى نفاد من "الكلمات".

هنا هو أبسط قليلا من التعليمات البرمجية العمل لا يمكن أن يأتي ، VB.NET.لاحظ أنه يجب أن تحقق سواء مجموعات البيانات لأن هناك مجموعتين من التقاط قوسين.

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

ملاحظة 1: ويل الجواب أعلاه هو نفس الفكرة مثل هذا واحد.نأمل أن هذا الجواب يشرح تفاصيل وراء المشهد أفضل قليلا :)

نصائح أخرى

Microsoft.VisualBasic.FileIO مساحة (في Microsoft.VisualBasic.dll) لديها TextFieldParser يمكنك استخدام تقسيم على مساحة delimeted النص.أنه يتعامل مع السلاسل داخل الاقتباس (أي "هذا هو رمز واحد" thisistokentwo) حسنا.

ملاحظة فقط لأن DLL يقول VisualBasic لا يعني يمكنك فقط استخدامه في VB المشروع.جزء من الإطار بأكمله.

هناك آلة الدولة النهج.

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

يمكن بسهولة أن تمتد لأشياء مثل متداخلة ونقلت الهروب.العودة كما IEnumerable<string> يسمح رمز فقط تحليل بقدر ما تحتاج إليه.لا يوجد أي سلبيات هذا النوع من كسول النهج سلاسل ثابتة حتى تعرف أن input لن تتغير قبل تحليل كل شيء.

انظر: http://en.wikipedia.org/wiki/Automata-Based_Programming

قد تحتاج أيضا إلى النظر في التعبيرات العادية.التي قد تساعدك على الخروج.هنا عينة انفصل من 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

كريغ هو الحق — استخدام التعبيرات العادية. Regex.تقسيم قد يكون أكثر إيجازا لتلبية الاحتياجات الخاصة بك.

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

باستخدام التعابير المنطقية بالتأكيد تبدو أفضل رهان ، ولكن هذا واحد فقط يعود السلسلة بأكملها.أنا أحاول أن يعدل ذلك ، ولكن ليس الكثير من الحظ حتى الآن.

string[] tokens = System.Text.RegularExpressions.Regex.Split(this.BuildArgs, @"[^\t]+\t|""[^""]+""\t");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top