2008-09-10 32 views
7

Tôi có chuỗi như thế nàyCách tốt nhất để phân tích không gian Ly Tiêu

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

Tôi muốn tokenize nó, tuy nhiên tôi không thể chỉ chia trên không gian. Tôi đã nghĩ ra một trình phân tích cú pháp hơi xấu xí, nhưng tôi tự hỏi liệu có ai có thiết kế thanh lịch hơn không.

Đây là trong C# btw.

EDIT: Phiên bản xấu xí của tôi, trong khi xấu xí, là O (N) và thực sự có thể nhanh hơn sử dụng 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

Hãy cho chúng tôi biết thêm về những gì bạn đang cố gắng hoàn thành, bao gồm lý do bạn không thể chia nhỏ không gian. Sau đó, chúng tôi có thể điều chỉnh câu trả lời cho tình huống của bạn. –

Trả lời

16

Thuật ngữ máy tính cho những gì bạn đang làm là lexical analysis; đọc điều đó để có một bản tóm tắt tốt về công việc chung này.

Dựa trên ví dụ của bạn, tôi đoán rằng bạn muốn khoảng trắng tách biệt các từ của bạn, nhưng nội dung trong dấu ngoặc kép phải được coi là "từ" không có dấu ngoặc kép.

Cách đơn giản nhất để làm điều này là để xác định một từ như là một biểu thức chính quy:

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

biểu hiện này khẳng định rằng một "từ" là một trong hai (1) không báo giá, văn bản không phải khoảng trắng bao quanh bởi khoảng trắng hoặc (2) văn bản không trích dẫn được bao quanh bởi dấu ngoặc kép (theo sau là một số khoảng trắng). Lưu ý việc sử dụng dấu ngoặc đơn để đánh dấu văn bản mong muốn.

Được trang bị regex đó, thuật toán của bạn rất đơn giản: tìm kiếm văn bản của bạn cho từ "tiếp theo" như được xác định bằng dấu ngoặc đơn và trả lại. Lặp lại điều đó cho đến khi bạn hết "từ".

Đây là bit làm việc đơn giản nhất mà tôi có thể đưa ra, trong VB.NET. Lưu ý rằng chúng tôi phải kiểm tra cả hai nhóm cho dữ liệu vì có hai tập hợp dấu ngoặc đơn.

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 

Lưu ý 1: Will's câu trả lời ở trên, cũng giống như ý tưởng này. Hy vọng câu trả lời này giải thích những chi tiết đằng sau sân khấu tốt hơn một chút :)

8

Không gian tên Microsoft.VisualBasic.FileIO (trong Microsoft.VisualBasic.dll) có TextFieldParser bạn có thể sử dụng để phân tách văn bản bị xóa không gian. Nó xử lý các chuỗi trong dấu ngoặc kép (tức là, "đây là một mã thông báo" thisistokentwo).

Lưu ý, chỉ vì DLL nói VisualBasic không có nghĩa là bạn chỉ có thể sử dụng nó trong một dự án VB. Một phần của toàn bộ khung công tác.

0

Bạn cũng có thể muốn xem xét các cụm từ thông dụng. Điều đó có thể giúp bạn. Dưới đây là một mẫu gạt từ 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 là đúng — sử dụng biểu thức thông thường. Regex.Split có thể ngắn gọn hơn cho nhu cầu của bạn.

0

[^ \ t] + \ t | "[^"] + "\ t

sử dụng Regex chắc chắn trông giống như đặt cược tốt nhất, tuy nhiên điều này chỉ trả về toàn bộ chuỗi.Tôi đang cố gắng tinh chỉnh nó, nhưng không có nhiều may mắn cho đến nay.

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

Điều này sẽ không hoạt động vì Regex.Split được thiết kế để chụp dựa trên dấu tách, không mã thông báo. Sử dụng Regex.Match để có được hiệu ứng mong muốn. –

3

Có cách tiếp cận máy trạng thái.

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

Nó có thể dễ dàng được mở rộng cho những thứ như báo giá lồng nhau và thoát. Trả lại là IEnumerable<string> cho phép mã của bạn chỉ phân tích cú pháp nhiều như bạn cần. Không có bất kỳ nhược điểm thực sự cho rằng cách tiếp cận lười biếng như dây là không thay đổi, do đó bạn biết rằng input sẽ không thay đổi trước khi bạn đã phân tích cú pháp toàn bộ điều.

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

Các vấn đề liên quan