Есть ли способ проанализировать строку поиска Google в табличной переменной в T-SQL? - PullRequest
1 голос
/ 07 декабря 2009

Есть ли способ проанализировать строку поиска Google в табличной переменной в T-SQL?

Под строкой поиска Google я подразумеваю операторы знака плюс (обязательный), знака минус (исключить) и точной фразы (двойные кавычки).

Например, следующая строка поиска:

one -two +three "four five" -"six seven" +"eight nine" "ten eleven twelve"

Будет проанализирован в табличной переменной, которую я мог бы использовать для генерации T-SQL, где:

OPERATOR    STRING
            one
-           two
+           three
            four five
-           six seven
+           eight nine
            ten eleven twelve

Спасибо!

Ответы [ 4 ]

2 голосов
/ 07 декабря 2009

Ну, парсеры пишутся одинаково на любом языке, используя конечный автомат. Нет ничего лучше, чем написать короткий синтаксический анализатор утром, чтобы смазать ваши синапсы:

declare @s varchar(max);
declare @t table (operator char(1) null, token varchar(max));

set @s = 'one -two +three "four five" -"six seven" +"eight nine" "ten eleven twelve"';

declare @state varchar(100);
declare @operator char(1);
declare @token varchar(max);
declare @c char(1);
declare @i int;

set @state = 'start';
set @i = -1;

while (1=1)
begin
  set @i = @i + 1;
  if (@i > len(@s))
    break;
  set @c = substring(@s, @i, 1);
  if (@state = 'start')
  begin
    if @c in ('-', '+')
    begin
      set @operator = @c;
      set @token = '';
      set @state = 'operator';
      continue;
    end
    else if @c = '"'
    begin
      set @operator = null;
      set @token = '';
      set @state = 'quote';
      continue;
    end
    else if (@c between 'a' and 'Z')
      or (@c between '0' and '9')
    begin
      set @operator = null;
      set @token = @c;
      set @state = 'token';
      continue;
    end
    else
      continue; -- ignore noise
  end
  else if @state = 'token'
  begin
    if (@c between 'a' and 'Z')
      or (@c between '0' and '9')
    begin
      set @token = @token + @c;
      continue;
    end
    else
    begin
      insert into @t (operator, token)
        values (@operator, @token); 
      set @state = 'start';
      continue;
    end
  end
  else if @state = 'quote'
  begin
    if (@c != '"')
    begin
      set @token = @token+@c;
      continue;
    end
    else
    begin
      insert into @t (operator, token)
        values (@operator, @token); 
      set @state = 'start';
      continue;
    end
  end
  else if @state = 'operator'
  begin
    if @c = '"'
    begin
      set @token = '';
      set @state = 'quote';
      continue;
    end
    else if (@c between 'a' and 'Z')
      or (@c between '0' and '9')
    begin
      set @token = @c;
      set @state = 'token';
      continue;
    end
    else 
    begin
      -- consider raising error here, invalid char after operator +/-
      set @state = 'start';
      continue;
    end
  end
  else
    raiserror ('Unexpected state %s', 16,2, @state);
end
if @state = 'token'
begin
  insert into @t (operator, token)
        values (@operator, @token); 
end
else if @state != 'start'
begin
  raiserror ('Incorrectly formatted string, must not end in state %s', 16, 1, @state);
end

select * from @t;
1 голос
/ 07 декабря 2009

Ремус вдохновил меня предложить собственное решение в виде табличной функции.

CREATE FUNCTION [dbo].[PARSE_SEARCH_STRING]
(   
    @search_string NVARCHAR(MAX) 
)
RETURNS @table_token TABLE (
    operator CHAR(1) NULL,
    token NVARCHAR(MAX)
)
AS
BEGIN

    DECLARE @token NVARCHAR(MAX)
    DECLARE @operator CHAR(1)
    DECLARE @remainder NVARCHAR(MAX)
    DECLARE @length INTEGER

    SET @remainder = LTRIM(RTRIM(@search_string))

    WHILE LEN(@remainder) > 0
    BEGIN

        IF SUBSTRING(@remainder, 1, 1) = '-' OR SUBSTRING(@remainder, 1, 1) = '+' OR SUBSTRING(@remainder, 1, 1) = '='
        BEGIN
            SET @operator = LTRIM(RTRIM(SUBSTRING(@remainder, 1, 1)))
            SET @remainder = LTRIM(RTRIM(SUBSTRING(@remainder, 2, LEN(@remainder) - 1)))
        END
        ELSE
            SET @operator = NULL

        IF SUBSTRING(@remainder, 1, 1) = '"'
        BEGIN
            SET @length = CHARINDEX('"', @remainder, 2) - 2
            IF NOT @length > 0 SET @length = LEN(@remainder)
            SET @token = LTRIM(RTRIM(SUBSTRING(@remainder, 2, @length)))
            SET @remainder = LTRIM(RTRIM(SUBSTRING(@remainder, 3 + @length, LEN(@remainder) - @length + 2)))
        END
        ELSE
        BEGIN
            SET @length = CHARINDEX(' ', @remainder, 1) - 1
            IF NOT @length > 0 SET @length = LEN(@remainder)
            SET @token = LTRIM(RTRIM(SUBSTRING(@remainder, 1, @length)))
            SET @remainder = LTRIM(RTRIM(SUBSTRING(@remainder, 1+ @length, LEN(@remainder) - @length + 2)))
        END

        IF NOT @token = ''
        BEGIN
            IF NOT EXISTS ( 
                SELECT 1 
                FROM @table_token 
                WHERE operator = @operator
                AND token = @token
            )
            INSERT @table_token ( operator, token ) VALUES ( @operator, @token )
        END

    END

    RETURN

END
1 голос
/ 07 декабря 2009

Вам нужно в основном вывести грамматику из этого формата и написать для нее быстрый анализатор. В сети должно быть много примеров. Я точно помню, что книга Б.Страуструпа на С ++ содержит пример простого калькулятора. Вы можете взглянуть на это.

0 голосов
/ 07 декабря 2009

Если вы находитесь в .net, пример Irony SQL FTS может помочь вам начать. Вы можете адаптировать сплиттер для создания ваших данных в базе данных

http://irony.codeplex.com/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...