Существует ли T-SQL-эквивалент для пунктуации, поскольку [0-9] для цифр, а [az] для букв?

8

Существует ли T-SQL-эквивалент шаблонов [0-9]and [a-z], который позволит мне извлекать значения из столбца, содержащего знаки пунктуации?

Например:

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

Это будет возвращать значения, где первые 3 символа являются числами от 0 до 9, а последний символ будет буквой между a и z, поэтому будет возвращать такие вещи, как 123aи, 456bно не будет возвращать значение 12ABC.

Я хочу знать, существует ли эквивалент для пунктуации, как [0-9]для чисел и [a-z]для букв, чтобы он возвращался AB!23и C?D789?

Если бы я мог использовать регулярное выражение, я мог бы использовать выражение ^[a-zA-Z0-9]*$для сопоставления буквенно-цифровых символов в строке.

Where       Value like '^[a-zA-Z0-9]*$'

Есть ли для этого эквивалент SQL?

Я знаю, что такое можно сделать в RegEx, но мне это нужно в T-SQL, я не могу загрузить какие-либо пользовательские сборки на этот сервер, поэтому не могу использовать регулярные выражения.

Настоящий столбец - это varchar (200) . Сличением является Latin1_General_CI_AS. Я использую SQL Server 2012 Standard Edition.

pix1985
источник
Давайте продолжим эту дискуссию в чате .
Соломон Руцкий

Ответы:

12

Самая большая трудность в достижении точного решения состоит в том, чтобы точно определить , какие символы должны быть включены (или исключены, в зависимости от того, какое направление имеет больше смысла для операции). Смысл:

  • Мы говорим о VARCHAR/ ASCII данных или NVARCHAR/ Unicode данных? Список знаков препинания для данных ASCII зависит от кодовой страницы, которая, в свою очередь, зависит от параметров сортировки. ( в этом вопросе мы имеем дело с данными ASCII ).
  • Имеем ли мы дело с поиском с учетом регистра или без учета регистра?
  • Какой Collation установлен для столбца? Сортировка покажет нам как кодовую страницу, так и регистр символов. ( в этом вопросе мы имеем дело сLatin1_General_CI_AS )
  • это термин «знаки препинания» означает только стандартные символы пунктуации (например ., ,, ;, :и т.д.) , или это значит не алфавитно-цифровые символы?
  • Включены ли пробельные символы?
  • Включены ли контрольные символы?
  • Как насчет валютных символов , таких , как ¢, £, ¥и т.д.?
  • А как насчет символов, таких как ©и ?
  • Какие символы считаются "альфа"? Не являются английские символы , такие как Â, É, Ñ, ß, Þвключены?
  • Поскольку этот Вопрос касается клавиатур Великобритании (см. Обсуждение этого вопроса), как насчет символа Æ/ æ?

Чтобы обеспечить ясность в отношении ожидаемого поведения, следующий запрос покажет все 256 символов набора символов Latin1 (т. Е. Кодовую страницу 1252) и то, как работают два варианта предлагаемого решения @ Shaneis . Первое поле (помеченное как Latin1_General_CI_AS) показывает LIKEпредложение, предложенное @Shaneis (на момент написания этой статьи), а второе поле (помеченное как Latin1_General_100_BIN2) показывает модификацию, в которой я переопределяю Collation для указания двоичного (то есть, Collation, заканчивающийся на _BIN2; _BINПараметры сортировки устарели, поэтому не используйте их, если у вас есть доступ к _BIN2версиям), что означало, что мне также нужно было добавить A-Zдиапазон, чтобы отфильтровать буквы в верхнем регистре, так как текущий параметр сортировки не учитывает регистр

;WITH nums AS
(
  SELECT TOP (256) (ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1) AS [Decimal]
  FROM   [master].[sys].[all_objects]
)
SELECT nm.[Decimal],
       CHAR(nm.[Decimal]) AS [Character],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9]%'
               THEN 'x' ELSE '' END AS [Latin1_General_CI_AS],
       CASE WHEN CHAR(nm.[Decimal]) LIKE '%[^a-z0-9A-Z]%' COLLATE Latin1_General_100_BIN2
               THEN 'x' ELSE '' END AS [Latin1_General_100_BIN2]
FROM   nums nm;

ОБНОВИТЬ

Следует отметить, что ЕСЛИ кто-то действительно стремится найти символы, которые классифицируются как «знаки пунктуации» (а не «символ валюты», «математический символ» и т. Д.), И если ЕСЛИ один не запрещает использовать SQLCLR / загрузку пользовательского Ассамблея (SQLCLR была введена с SQL Server 2005, и я еще не сталкивался с хорошей причиной, что не позволяю ему, тем более , что Azure SQL Database V12 поддерживает SAFEсборку), то вы можете использовать регулярные выражения, но не по той причине , что большинство людей догадался бы.

Вместо использования регулярных выражений для создания более функционального диапазона символов или даже вместо использования чего-то вроде \w(означающего любой «слово»), вы можете указать категорию Unicode символов, по которым вы хотите фильтровать, и есть несколько определенных категорий :

https://www.regular-expressions.info/unicode.html#category

Вы даже можете указать блок Unicode для фильтрации, например, «InBengali» или «InDingbats» или «InOptical_Character_Recognition» и т. Д .:

https://www.regular-expressions.info/unicode.html#block

Существует множество примеров создания функций RegEx для SQL Server (хотя большинство примеров не соответствуют рекомендациям SQLCLR), или вы можете скачать бесплатную версию библиотеки SQL # (которую я создал) и использовать скалярную функцию RegEx_IsMatch следующим образом :

SQL#.RegEx_IsMatch(Unicode-String-Expression, N'\p{P}', 1, NULL)

В \p{P}выражение означает \p= Unicode Категория, а {P}= все знаки препинания (в отличие от конкретного типа пунктуации, такие как «Connector Пунктуации»). И в категорию «Знаки пунктуации» входят все знаки препинания на всех языках! Вы можете увидеть полный список на сайте Unicode.org по следующей ссылке (в настоящее время в этой категории 717 кодов):

http://unicode.org/cldr/utility/list-unicodeset.jsp?a=%5B%3AGeneral_Category%3DPunctuation%3A%5D

Обновленная версия тестового запроса было показано выше, в том числе и другое поле , которое использует SQL # .RegEx_IsMatch с \p{P}, и результаты всех 3 -х тестов на всех 256 символов кодовой страницы 1252 (т.е. Latin1_General) была размещена на PasteBin.com по адресу:

T-SQL-запрос и результаты для фильтрации типов символов


ОБНОВЛЕНИЕ
Следующее было упомянуто в связанной дискуссии:

Вы хорошо отметили символы с акцентом, так как они являются именами отелей со всего мира, в именах будут символы с акцентом, для моей проблемы я бы хотел классифицировать их как допустимых буквенных символов.

В этом случае:

  1. Есть 11 неанглийских символов, которые включены в набор символов Latin1 / Кодовую страницу, которые не соответствуют a-zдиапазону. Они являются: ð Ð Þ þ œ Œ š Š ž Ž Ÿ. Их необходимо добавить к шаблону, и хотя в данный момент это не нужно, добавление не повредит, A-Zтак что шаблон работает так же хорошо с учетом регистра с учетом регистра. Конечный результат:
    LIKE '%[^a-zA-Z0-9ðÐÞþœŒšŠžŽŸ]%'

  2. Учитывая, что в эти данные могут входить «названия отелей со всего мира», я настоятельно рекомендую изменить тип данных столбца, чтобы NVARCHARможно было хранить все символы из всех языков. Принимая это во внимание, VARCHARсуществует очень высокий риск возможной потери данных, поскольку вы можете представлять только языки на основе латинского алфавита, и даже не полностью для тех, которые имеют шесть дополнительных категорий Unicode, которые предоставляют дополнительные символы, относящиеся к латинскому алфавиту.

Соломон Руцкий
источник
5

Я, возможно, немного упрощаю это, но, если мы говорим, что пунктуация - это все, что остается, когда алфавитно-цифровые значения удаляются, то следующее будет искать строки, содержащие не алфавитно-цифровые символы.

Create Table #Test
(
Value   VarChar(10)
) 
Insert Into #Test
Values ('123a'), ('456b'), ('12ABC'),('AB!23'),('C?D789')

-- Original
Select      *
From        #Test
Where       Value like '[0-9][0-9][0-9][a-z]'

-- Non Alpha-numeric
SELECT * FROM #Test WHERE Value LIKE '%[^a-z0-9]%';

DROP TABLE #Test;
Shaneis
источник