2009-12-10 11 views
9

私はGoogleと同じような検索クエリをトークン化することを検討しています。私は、次の検索クエリを持っている場合たとえば、:Googleのような検索クエリトークン化と文字列分割

the 
quick 
brown fox 
jumps 
over 
the 
lazy dog 

あなたが見ることができるように、トークンは中でスペースを維持:

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

は、私は、次のトークンを持つ文字列配列を持っていると思います二重引用符。

私はC#でこれを行う方法の例を探していますが、できれば正規表現を使用しないことをお勧めします。

また、これを拡張して他の特殊文字を扱う方法を知りたいと思います。たとえば、検索クエリからの除外などを強制する用語の前に - を付けます。このような文字列をcharで

+0

、二重引用符( ")がマルチワードトークンを示す以外にも他の場所で使用することができますか?私の目的のために –

+0

、いいえ、それはできません。 – jamesaharvey

答えて

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

この方法の実際の利点は、簡単に "を含めるようにextenedすることができています - "のような要件:

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

今、私は次のguと同じくらいRegexを読むのが嫌いですYが、あなたはそれを分割している場合、この1つは読みするのは非常に簡単です:

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

説明

  1. 可能一致した場合、「次までのすべてのものが続く続くマイナス記号、次の「
  2. は、そうでなければ一致するまで、すべてのものに続く「
  3. は、それ以外の場合は一致」 - 任意の単語に続く文字を
  4. それ以外の場合は一致私はほんの数日前にこれを行う方法を把握しようとして
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

私は、これは私が考えていたかについておおまかだと思います正規表現が十分でない場合。 しかし、I **非常に強く**は、その単語が文字列ではないお勧めします。あなたが原因の文字列の不変性に狂ったような文字列を割り当てるとしている。より良い偶数ワード文字列ビルダまたはを作成します文字列だけです –

+1

あなたは正しいですが、これは擬似コードであり、原則です。 – VDVLeon

1

あなたは

  • グループ
  • に結果を置くことができる限り多くの単語文字は、任意の次の空白文字を飲み込みます。私はMicrosoft.VisualBasic.FileIO.TextFieldParserを使用して終了しました。これは、私が望むものを正確に(ちょうどHasFieldsEnclosedInQuotesをtrueに設定して)行いました。確かに、C#プログラムで「Microsoft.VisualBasic」を使用するのはいくぶん奇妙に見えますが、それは機能し、.NETフレームワークの一部であると言えます。

    私の文字列をTextFieldParserのストリームに入れるには、 "新しいMemoryStream(新しいASCIIEncoding()。GetBytes(stringvar))"を使用しました。これが最良の方法であるかどうかは不明です。

    編集:私はこれがあなたのハンドルとは思わない「 - 」の要件を、ので、多分正規表現ソリューションは、私はこの問題へのJavaソリューションを探していると@Michaelを使用して解決策を考え出したた

  • 0

    優れています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; 
    }