Извлечение подстроки из строки в SQL

#sql #regex #tsql #sql-server-2008

#sql #регулярное выражение #tsql #sql-server-2008

Вопрос:

Мне нужно извлечь текст, окруженный ***[some text] строками, как в следующем примере:

 some text
some text
***[some text]
THIS SHOULD BE EXTRACTED
***[some text]
some text
some text
some text
some text
some text
***[some text]
THIS SHOULD BE EXTRACTED TOO
***[some text]
some text
  

вывод должен быть:

 THIS SHOULD BE EXTRACTED
THIS SHOULD BE EXTRACTED TOO
  

Я пробовал PATINDEX , как здесь, но не смог найти способ извлечь строку.

 PATINDEX('%[*][*][*][[]%]%%[*][*][*][[]%]%',@Text)
  

Я с нетерпением жду любых предложений.

Комментарии:

1. Отображаемый текст представляет собой поле, строку или набор строк?

2. @Cos Callis Представляет одно NVARCHAR поле

3. Есть CR LF в конце этих строк?

4. @DKnight там есть char(10) символ, но приветствуется любой пример, работающий с однострочным текстом

5. И разделитель начального раздела действительно точно такой же, как разделитель конечного раздела?

Ответ №1:

Для несколько более простого случая, рассмотренного в комментариях, вы могли бы сделать

 ;WITH T(C) AS
(
 SELECT '
    some text
    some text
    ***[some text 1]
    THIS SHOULD BE EXTRACTED
    ***[some text 2]
    some text
    some text
    some text
    some text
    some text
    ***[some text 1]
    THIS SHOULD BE EXTRACTED TOO
    ***[some text 2]
    some text'
)
SELECT col.value('.','varchar(max)')
FROM T
CROSS APPLY (SELECT CAST('<a keep="false">'   
                        REPLACE(
                            REPLACE(C,'***[some text 2]','</a><a keep="false">'),
                        '***[some text 1]','</a><a keep="true">')   
                    '</a>' AS xml) as xcol) x
CROSS APPLY xcol.nodes('/a[@keep="true"]') tab(col)
  

Комментарии:

1. Я протестировал ваше решение по сравнению с моим, которое приведено выше. Это занимает 98% пакета. У меня всего лишь 2%. Я думаю, это из-за XML.

2. Да, XML функции чтения определенно не обладают высокой производительностью. Кроме того, для моего ответа потребовалось бы еще несколько REPLACE операций, если текст может содержать символы, такие как < , чтобы заменить их соответствующими объектами XML.

Ответ №2:

Не решение для регулярных выражений, и я все еще новичок в SQL, поэтому это может быть неоптимально, но вы должны иметь возможность выполнять синтаксический анализ с WHILE циклом, используя

CHARINDEX для *** затем использовать это в качестве отправной точки для
CHARINDEX для LF Использования этого в качестве отправной точки для
SUBSTRING с конечной точкой, являющейся CHARINDEX следующего ***
присоедините подстроку к вашему выводу, перейдите к концу *** и выполните цикл, чтобы найти следующую.

Я немного поиграю с этим и посмотрю, смогу ли добавить пример.
РЕДАКТИРОВАТЬ — Вероятно, для этого требуется дополнительная проверка ошибок

 declare @inText nvarchar(2000) = 'some text 
some text 
***[some text] 
THIS SHOULD BE EXTRACTED 
***[some text] 
some text 
some text 
some text 
some text 
some text 
***[some text] 
THIS SHOULD BE EXTRACTED TOO 
***[some text] 
some text '

declare @delim1 nvarchar(50) = '***'
declare @delim2 char = char(10)
declare @output nvarchar(1000) = ''
declare @position int
declare @positionEnd int

set @position = CHARINDEX(@delim1,@inText)
while (@position != 0 and @position is not null)
BEGIN
  set @position = CHARINDEX(@delim2,@inText,@position)
  set @positionEnd = CHARINDEX(@delim1,@inText,@position)
  set @output = @output   SUBSTRING(@inText,@position,@positionEnd-@position)
  set @position = CHARINDEX(@delim1,@inText,@positionEnd LEN(@delim1))
END
select @output
  

Комментарии:

1. Я думаю, вероятно, вы могли бы использовать это в качестве основы , а затем вызвать UDF с помощью CROSS APPLY

2. @Martin — оооо дополнительные материалы для чтения — спасибо за отзыв, это очень ценится

Ответ №3:

Вы можете найти это в моем блоге:http://sql-tricks.blogspot.com/2011/04/extract-strings-with-delimiters.html Это чистое решение без каких-либо дополнительных изменений, только последовательности разделителей должны быть декалированы.

Комментарии:

1. Спасибо, ваше решение хорошее, но я получаю Invalid length parameter passed to the SUBSTRING function , когда пытаюсь изменить разделители в соответствии со своими потребностями. Также это немного медленно или мой сервер работает медленно, я не уверен.

2. Пожалуйста, напишите свои разделители. Я это исправлю.

Ответ №4:

Возможно, я ошибаюсь, но я не думаю, что есть чистый способ сделать это непосредственно в SQL. Я бы использовал хранимую процедуру CLR и использовал регулярные выражения из C # или вашего языка .NET по выбору.

Смотрите Эту статью (или this article) для соответствующего примера использования регулярных выражений.

Комментарии:

1. К сожалению, я не могу использовать хранимые процедуры C # или CLR, я могу выполнять только инструкции select…

2. Ссылка на статью msdn.microsoft.com/en-us/magazine/cc163473.aspx нарушено 🙁

3. @RobertLujo Я нашел другой пример здесь на blogs.msdn.microsoft.com/sqlclr/2005/06/29 /…

Ответ №5:

Я полагаю, вы можете использовать xp_regex_match, как описано в http://www.codeproject.com/KB/mcpp/xpregex.aspx?q=use sql function to parse text для анализа вашего поля nvarchar. Я написал нечто подобное довольно давно.