#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. Я написал нечто подобное довольно давно.