2008-09-10 10 views
7

私はこのような文字列を持っているスペースで区切られたテキストを解析する最適な方法

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

私はそれをトークン化したいが、私はスペースを分割することはできない。私は幾分醜いパーサーを思いついたが、誰かがもっとエレガントなデザインをしているのだろうかと思っている。

これはC#btwです。

編集:私の醜いバージョンは、醜いですが、O(N)であり、実際にはRegExを使用するよりも高速かもしれません。

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();    
} 
+0

は私たちに、あなたがスペースで分割することができない理由を含め、達成しようとしているものについての詳細を教えてください。それから、あなたの状況に対する答えを調整することができます。 –

答えて

16

お使いのコンピュータの用語はlexical analysisです。この共通の課題の良い要約については、それを読んでください。

あなたの例に基づいて、空白で単語を区切りたいと思っていますが、引用符で囲まれたものは引用符なしで "単語"として扱われるべきです。

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

この式は、「言葉」は、(1)非引用、非空白文字に囲まれてのいずれかであると述べている:

これを行う最も簡単な方法は、正規表現として単語を定義することです空白、または(2)引用符で囲まれた引用符で囲まれていないテキスト(その後に空白が続く)目的のテキストを強調表示するためにキャプチャ括弧を使用することに注意してください。

この正規表現で武装されているアルゴリズムは簡単です。キャプチャしたカッコで定義されている次の "単語"をテキストで検索して返します。あなたは "言葉"が足りなくなるまでそれを繰り返します。

ここではVB.NETで思​​いついた作業コードの中で最も単純なものがあります。 両方のデータをのグループにチェックする必要があることに注意してください。キャプチャカッコが2セットあるためです。

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:Will's上記の回答は上記と同じです。うまくいけば、この答えは、シーン少し良く:)

8

Microsoft.VisualBasic.FileIO名前空間を使用すると、スペースdelimetedテキストに分割するために使用することができますTextFieldParserを持っています。引用符内の文字列を処理します(つまり、thisistokentwoは「これは1トークンです」)。

DLLはVisualBasicがVBプロジェクトでのみ使用できるとは限りません。フレームワーク全体の一部。

0

正規表現を調べることもできます。それはあなたを助けるかもしれません。ここではサンプルは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 
0

Craigは、正規表現を使用する権利—です。 Regex.Splitは、お客様のニーズにより簡潔になる場合があります。

0

[^ \ t]は+ \ tの後ろに詳細を説明| "[^"] + "\トン

正規表現は間違いのように見える使用私はそれを微調整しようとしていますが、これまでのところはあまり運がありません。

string[] tokens = System.Text.RegularExpressions.Regex.Split(this.BuildArgs, @"[^\t]+\t|""[^""]+""\t"); 
+0

Regex.Splitはトークンではなくセパレータに基づいてキャプチャするように設計されているため、これは機能しません。 Regex.Matchを使用して目的の効果を得ます。 –

3

ステートマシンのアプローチがあります。

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

関連する問題