【问题标题】:Howto: C# string to SQL full-text catalog search?如何:C# 字符串到 SQL 全文目录搜索?
【发布时间】:2010-07-10 02:21:12
【问题描述】:

我有一些这样的搜索查询:

乔治而不是华盛顿或亚伯拉罕

狗或猫而不是狼

对于这些搜索,我希望返回 George 或 Abraham 但不是 Washington 等的结果。

基本上,我想获取字符串并能够将上下文搜索提交到我的全文目录存储过程搜索。

我假设我应该使用 Regex,但我对 C# 中的 Regex 非常不熟悉。

我找到了这篇文章:http://support.microsoft.com/kb/246800,我认为这是我需要做的,但我希望我能在实施方面得到一些帮助。

假设您将字符串作为参数并希望返回一个字符串:

string input = 'George Washington AND NOT Martha OR Dog';

private string interpretSearchQuery(input)
{
     // HALP!

        /* replace ' AND ' | ' AND NOT ' with
         * " AND "
         * " AND NOT "
         * 
         * replace ' OR ' | ' OR NOT ' with
         * " OR "
         * " OR NOT "
         * 
         * add " to beginning of string and " to end of string
         */

     return '"George Washington" AND NOT "Martha" OR "Dog"';
}

【问题讨论】:

  • interpretSearchQuery 到底应该做什么?输入是什么?预期的输出是什么?
  • 我会在 Space 上拆分它,并且任何不是 AND NOT 或 OR 我会在前面加上“LIKE '%”并附加“%'”的数组项,然后用空格将它内爆回来并将其添加到 sql 查询的末尾。好吧,实际上我不会做这样的事情,但谁知道......它可能会起作用。
  • @Oded 我添加了更多信息,抱歉。基本上我想获取输入并将其转换为可用于从 Sql Server 全文搜索中获取正确结果的方式。

标签: c# sql-server full-text-search


【解决方案1】:

我会使用Postfix notation(或波兰表示法)解析您的字符串。

**Postfix algorithm**
The algorithm for evaluating any postfix expression is fairly straightforward:

While there are input tokens left    

  Read the next token from input.

  If the token is a value
    Push it onto the stack.

  Otherwise, the token is an operator (operator here includes both operators, and functions). 
   It is known a priori that the operator takes n arguments. 

   If there are fewer than n values on the stack 
     (Error) The user has not input sufficient values in the expression. 
   Else, Pop the top n values from the stack. 

   Evaluate the operator, with the values as arguments. 
   Push the returned results, if any, back onto the stack. 

If there is only one value in the stack 
  That value is the result of the calculation. 

If there are more values in the stack 
  (Error) The user input has too many values.

所以取你的输入字符串:

'George Washington AND NOT Martha OR 狗'

并将其简化为:

A = George 
B = Washington
C = Martha
D = Dog
& = AND
! = NOT
| = OR

我们会得到 ​​p> 的后缀符号

AB&C!D|

这意味着:

  1. 推送值 A(乔治)
  2. 推动价值 B(华盛顿)
  3. AND 通过弹出前两个值 并推动结果(乔治和 华盛顿)
  4. 推送值 C(玛莎)
  5. 不是通过弹出前两个值 并推动结果(乔治和 华盛顿)不是(玛莎)
  6. 推送值 D(狗)
  7. 或通过弹出前两个值 并推动结果((乔治和 华盛顿)不是(玛莎))或(狗)

【讨论】:

  • 这是我最初的想法,我只是希望有一个用正则表达式代替的好方法。
  • 一旦你编写了一个快速解析器来获取你的查询字符串并返回一个后缀数组,查询就非常简单了。
  • 我打算用这个方法,很聪明的办法。
【解决方案2】:

这可能会让你开始......我会重构这个废话,使其更健壮。

string input = "George Washington AND NOT Martha OR Dog";

private string interpretSearchQuery(string input)
{
    StringBuilder builder = new StringBuilder();
    var tokens = input.Split( ' ' );

    bool quoteOpen = false;
    foreach( string token in tokens )
    {
        if( !quoteOpen && !IsSpecial( token ) )
        {
            builder.AppendFormat( " \"{0}", token );
            quoteOpen = true;
        }
        else if( quoteOpen && IsSpecial( token ))
        {
            builder.AppendFormat( "\" {0}", token );
            quoteOpen = false;
        }
        else
        {
            builder.AppendFormat( " {0}", token );
        }
    }

    if( quoteOpen )
    {
        builder.Append( "\"" );
    }

    return "'" + builder.ToString().Trim() + "'";
}

public static bool IsSpecial( string token )
{
    return string.Compare( token, "AND", true ) == 0 ||
        string.Compare( token, "OR", true ) == 0 ||
        string.Compare( token, "NOT", true ) == 0;
}

【讨论】:

  • 你的概念启发了我。我的解决方案并不像使用 postfix 那样完美,但它可以完成工作。
  • @samandmoore 我也会选择后缀答案!这是一个比这个 hack 更好的“通用”解决方案。
【解决方案3】:

这是我想出的解决方案。唯一的问题是格式错误的搜索查询将无法正确解析并失败:

private string interpretSearchTerm(string searchTerm)
        {
            string term = "";
            /* replace ' AND ' | ' AND NOT ' with
             * " AND "
             * " AND NOT "
             * 
             * replace ' OR ' | ' OR NOT ' with
             * " OR "
             * " OR NOT "
             * 
             * add " to beginning of string and " to end of string
             */
            if (searchTerm.IndexOf("AND") > -1
                || searchTerm.IndexOf("OR") > -1
                || searchTerm.IndexOf("AND NOT") > -1
                || searchTerm.IndexOf("OR NOT") > -1)
            {
                term = searchTerm.Replace(" AND NOT ", "\"AND NOT\"")
                        .Replace(" AND ", "\"AND\"")
                        .Replace(" OR NOT", "\"OR NOT\"")
                        .Replace(" OR ", "\"OR\"");
                term = "\"" + term + "\"";
                return term;
            }
            else if (searchTerm.IndexOf("\"") > -1) return searchTerm;
            else return "\"" + searchTerm + "\"";
        }

我现在将着手实现 GalacticJello 建议的后缀算法。我会在它工作时发布它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多