代码之家  ›  专栏  ›  技术社区  ›  jamesaharvey

类似谷歌的搜索查询标记化技术和字符串拆分

  •  9
  • jamesaharvey  · 技术社区  · 16 年前

    我想标记一个搜索查询,类似于谷歌的做法。例如,如果我有以下搜索查询:

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

    我想要一个带有以下标记的字符串数组:

    the
    quick
    brown fox
    jumps
    over
    the
    lazy dog
    

    如您所见,标记用双引号保留空格。

    我在找一些例子来说明如何在C语言中做到这一点,最好不要使用正则表达式,但是如果这是最有意义的,也是最有性能的,那么就这样吧。

    另外,我想知道如何扩展它来处理其他特殊字符,例如,将-放在术语前面以强制从搜索查询中排除等等。

    4 回复  |  直到 16 年前
        1
  •  13
  •   Michael La Voie Frederik Gheysels    16 年前

    到目前为止,这看起来是一个很好的regex的候选者。如果它变得非常复杂,那么可能需要一个更复杂的标记化方案,但是除非必要,否则您应该避免这条路线,因为这是一个非常多的工作。(另一方面,对于复杂的模式,regex很快就会变成一只狗,同样应该避免)。

    此regex应解决您的问题:

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

    以下是它的用法示例:

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

    现在我讨厌读雷杰克斯和下一个家伙一样多,但如果你把它分开,这本书很容易读:

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

    解释

    1. 如果可能的话,匹配一个减号,后面跟一个“在下一个之前都要跟在后面”
    2. 否则,匹配“后跟所有内容直到下一个”
    3. 否则匹配a-后跟任何单词字符
    4. 否则,请尽可能多地匹配单词字符
    5. 将结果分组
    6. 吞下下列空格字符
        2
  •  1
  •   VDVLeon    16 年前

    按字符转到字符串,如下所示:(伪代码排序)

    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
    
        3
  •  1
  •   psm321    16 年前

    几天前我只是想知道怎么做。我最终使用了Microsoft.VisualBasic.FileIO.TextFieldParser,它完全满足了我的需要(只需将hasFieldsEnclosedinQuotes设置为true)。当然,在C程序中使用“microsoft.visualBasic”看起来有点奇怪,但它确实有效,据我所知,它是.NET框架的一部分。

    为了将字符串放入textfieldParser流中,我使用了“new memoryStream(new asciiEncoding().getBytes(stringVar))”。不确定这是不是最好的方法。

    编辑:我不认为这能满足您的“-”要求,所以也许regex解决方案更好

        4
  •  0
  •   wsams    12 年前

    我正在寻找一个解决这个问题的Java解决方案,并想出了一个使用米迦勒La VoIE的解决方案。我想我会在这里分享它,尽管这个问题被问到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;
    }