2009-12-10 22 views
9

Tôi đang tìm cách mã thông báo truy vấn tìm kiếm tương tự như cách Google thực hiện. Ví dụ, nếu tôi có các truy vấn tìm kiếm sau:Mã thông báo truy vấn tìm kiếm giống như Google và tách chuỗi

the quick "brown fox" jumps over the "lazy dog" 

Tôi muốn có một mảng chuỗi với các thẻ sau:

the 
quick 
brown fox 
jumps 
over 
the 
lazy dog 

Như bạn có thể thấy, các thẻ bảo tồn không gian với trong dấu ngoặc kép.

Tôi đang tìm một số ví dụ về cách tôi có thể thực hiện điều này trong C#, tốt nhất là không sử dụng cụm từ thông dụng, tuy nhiên, điều đó có ý nghĩa nhất và sẽ là người biểu diễn nhất.

Ngoài ra, tôi muốn biết cách tôi có thể mở rộng điều này để xử lý các ký tự đặc biệt khác, ví dụ, đặt dấu - trước cụm từ để buộc loại trừ khỏi truy vấn tìm kiếm, v.v.

+0

Trong cú pháp của bạn, có thể nhân vật kép (") được sử dụng bất cứ nơi nào khác ngoài cho thấy một chữ đa thẻ? –

+0

Đối với mục đích của tôi, không có nó không thể. – jamesaharvey

Trả lời

13

Cho đến nay, điều này có vẻ giống như một ứng cử viên tốt cho RegEx của. Nếu nó phức tạp hơn một cách đáng kể, thì một lược đồ mã thông báo phức tạp hơn có thể cần thiết, nhưng bạn nên tránh lộ trình đó trừ khi cần thiết vì nó hoạt động hiệu quả hơn đáng kể. (mặt khác, đối với các lược đồ phức tạp, regex nhanh chóng biến thành một con chó và cũng nên tránh).

regex này nên giải quyết vấn đề của bạn:

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

Đây là một C# ví dụ về việc sử dụng của nó:

string data = "the quick \"brown fox\" jumps over the \"lazy dog\""; 
string pattern = @"(""[^""]+""|\w+)\s*"; 

MatchCollection mc = Regex.Matches(data, pattern); 
foreach(Match m in mc) 
{ 
    string group = m.Groups[0].Value; 
} 

Lợi ích thực sự của phương pháp này là nó có thể dễ dàng extened đưa bạn " - "yêu cầu như vậy:

string data = "the quick \"brown fox\" jumps over " + 
       "the \"lazy dog\" -\"lazy cat\" -energetic"; 
string pattern = @"(-""[^""]+""|""[^""]+""|-\w+|\w+)\s*"; 

MatchCollection mc = Regex.Matches(data, pattern); 
foreach(Match m in mc) 
{ 
    string group = m.Groups[0].Value; 
} 

Bây giờ tôi ghét đọc Regex nhiều như gu tiếp theo y, nhưng nếu bạn chia nó lên, chương trình này là khá dễ dàng để đọc:

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

Giải thích

  1. Nếu có thể phù hợp với một dấu trừ, theo sau là một "theo sau tất cả mọi thứ cho đến khi tiếp theo "
  2. Nếu không, hãy khớp với" theo sau là mọi thứ cho đến "
  3. Nếu không khớp với - theo sau là bất kỳ ký tự từ nào
  4. Nếu không khớp như nhiều nhân vật từ như bạn có thể
  5. Đặt kết quả trong một nhóm
  6. Swallow lên bất kỳ ký tự không gian sau
1

Go char bởi char vào chuỗi như thế này: (loại mã giả)

array words = {} // empty array 
string word = "" // empty word 
bool in_quotes = false 
for char c in search string: 
    if in_quotes: 
     if c is '"': 
      append word to words 
      word = "" // empty word 
      in_quotes = false 
     else: 
      append c to word 
    else if c is '"': 
     in_quotes = true 
    else if c is ' ': // space 
     if not empty word: 
      append word to words 
      word = "" // empty word 
    else: 
     append c to word 

// Rest 
if not empty word: 
    append word to words 
+1

Tôi nghĩ rằng đây là khoảng về những gì tôi đã suy nghĩ nếu regex không đủ, Tuy nhiên, tôi ** rất mạnh ** đề nghị từ đó không phải là một chuỗi. Bạn sẽ phân bổ các chuỗi như điên do bất biến của các chuỗi. –

+1

Bạn nói đúng, nhưng đây là mã giả Nó là về nguyên tắc. – VDVLeon

1

Tôi chỉ cố gắng tìm ra cách để làm điều này một vài ngày trước. Tôi đã kết thúc bằng cách sử dụng Microsoft.VisualBasic.FileIO.TextFieldParser đã làm chính xác những gì tôi muốn (chỉ cần đặt HasFieldsEnclosedInQuotes thành true). Chắc chắn nó có vẻ hơi lạ khi có "Microsoft.VisualBasic" trong một chương trình C#, nhưng nó hoạt động, và theo như tôi có thể nói nó là một phần của khuôn khổ .NET.

Để đưa chuỗi của tôi vào luồng cho TextFieldParser, tôi đã sử dụng "MemoryStream mới (new ASCIIEncoding(). GetBytes (stringvar))". Không chắc chắn nếu đây là cách tốt nhất để làm điều đó.

Chỉnh sửa: Tôi không nghĩ rằng đây sẽ xử lý của bạn "-" yêu cầu, như vậy có lẽ là giải pháp RegEx là tốt hơn

0

tôi đang tìm kiếm một giải pháp Java cho vấn đề này và đã đưa ra một giải pháp sử dụng @ Michael La Voie. Tôi nghĩ rằng tôi sẽ chia sẻ nó ở đây mặc dù câu hỏi được hỏi trong C#. Hy vọng không sao.

public static final List<String> convertQueryToWords(String q) { 
    List<String> words = new ArrayList<>(); 
    Pattern pattern = Pattern.compile("(\"[^\"]+\"|\\w+)\\s*"); 
    Matcher matcher = pattern.matcher(q); 
    while (matcher.find()) { 
     MatchResult result = matcher.toMatchResult(); 
     if (result != null && result.group() != null) { 
      if (result.group().contains("\"")) { 
       words.add(result.group().trim().replaceAll("\"", "").trim()); 
      } else { 
       words.add(result.group().trim()); 
      } 
     } 
    } 
    return words; 
} 
Các vấn đề liên quan