2009-12-10 35 views
9

我正在尋找類似於Google如何標記化搜索查詢。舉例來說,如果我有以下搜索查詢:類似Google的搜索查詢標記化和字符串拆分

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

我想有一個字符串數組以下的標記:

the 
quick 
brown fox 
jumps 
over 
the 
lazy dog 

正如你所看到的,令牌保護與空間雙引號。

我正在尋找一些如何在C#中完成此操作的示例,最好不要使用正則表達式,但如果這樣做最有意義並且性能最高,那麼就這樣吧。

另外我想知道如何擴展它來處理其他特殊字符,例如,在術語的前面強制排除搜索查詢等。

+0

在你的語法,可以在雙引號(「)的其他任何地方使用,除了說明令牌多字? – 2009-12-10 19:03:39

+0

對於我而言,沒有它做不到。 – jamesaharvey 2009-12-10 19:04:48

回答

13

到目前爲止,這看起來像一個很好的候選人正則表達式的。如果它變得複雜得多,那麼可能需要一個更復雜的標記化方案,但除非必要,否則您應該避開該路線,因爲它的工作量要大得多。 (另一方面,對於複雜的模式,正則表達式很快就會變成一隻狗,同樣應該避免)。

此正則表達式應該解決您的問題:

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

這裏是其使用的C#示例:

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

這種方法的真正好處是它可以很容易推廣的,包括你的「 - 「的要求是這樣的:

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

現在我討厭閱讀正規表達式的下一個顧Y,但如果你把它分解了,這個人是很容易閱讀:

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

說明

  1. 如果可能的匹配一個減號,然後是「後面的一切,直到下一個「
  2. 否則匹配」,後面的一切,直到下一個「
  3. 否則匹配 - 其次是任何文字字符
  4. 否則匹配儘可能多的單詞字符,你可以
  5. 把結果一組
  6. 在吞掉任何下列空格字符
1

轉到焦成炭像這樣的字符串:(排序的僞代碼)

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

我想,這大概約我在想什麼如果正則表達式不充分 但是,我非常強烈地推薦這個詞不是一個字符串,由於字符串的不變性,您將分配字符串像瘋了一樣。只是一串字符 – 2009-12-10 19:42:31

+1

你是對的,但這是僞代碼,是關於原理的。 – VDVLeon 2009-12-11 14:28:17

1

我只是想弄清楚如何做到這一點,前幾天。我結束了使用Microsoft.VisualBasic.FileIO.TextFieldParser,這正是我想要的(只需將HasFieldsEnclosedInQuotes設置爲true)。當然,在C#程序中使用「Microsoft.VisualBasic」看起來有些奇怪,但它可以工作,並且據我所知它是.NET框架的一部分。爲了讓我的字符串成爲TextFieldParser的流,我使用了「新的MemoryStream(new ASCIIEncoding()。GetBytes(stringvar))」。不知道這是否是最好的方式。

編輯:我不認爲這會處理你的「 - 」的要求,所以也許正則表達式的解決方案是更好的

0

我一直在尋找一個Java解決這一問題,並使用@邁克爾的解決方案上來La Voie's。儘管在C#中要求提出問題,但我還是想在此分享它。希望沒關係。

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