Basamak olmayanlar neden GİBİ [0-9]?


13

Sunucumun varsayılan harmanlaması şu sorgu tarafından belirlendiği şekliyle Latin1_General_CI_AS:

SELECT SERVERPROPERTY('Collation') AS Collation;

Bu harmanlama ile yüklemi kullanarak dizelerdeki rakam olmayan karakterlerle eşleşebildiğimi keşfetmekten şaşırdım LIKE '[0-9]'.

Neden varsayılan harmanlamada bu oluyor? Bunun yararlı olacağı bir durum düşünemiyorum. İkili bir harmanlama kullanarak davranışa çalışabileceğimi biliyorum, ancak varsayılan harmanlamayı uygulamak için garip bir yol gibi görünüyor.

Rakamları filtrelemek rakam içermeyen karakterler oluşturur

Tüm olası tek baytlık karakter değerlerini içeren bir sütun oluşturarak ve değerleri basamak eşleme yüklemiyle filtreleyerek davranışı gösterebilirim.

Aşağıdaki ifade, geçerli kod sayfasındaki her kod noktası için bir tane olmak üzere 256 satırlı geçici bir tablo oluşturur:

WITH P0(_) AS (SELECT 0 UNION ALL SELECT 0),
P1(_) AS (SELECT 0 FROM P0 AS L CROSS JOIN P0 AS R),
P2(_) AS (SELECT 0 FROM P1 AS L CROSS JOIN P1 AS R),
P3(_) AS (SELECT 0 FROM P2 AS L CROSS JOIN P2 AS R),
Tally(Number) AS (
  SELECT -1 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))
  FROM P3
)
SELECT Number AS CodePoint, CHAR(Number) AS Symbol
INTO #CodePage
FROM Tally
WHERE Number >= 0 AND Number <= 255;

Her satır, kod noktasının tamsayı değerini ve kod noktasının karakter değerini içerir. Karakter değerlerinin tümü görüntülenebilir değildir - bazı kod noktaları kesinlikle kontrol karakteridir. İşte çıktısının seçici bir örneği SELECT CodePoint, Symbol FROM #CodePage:

0   
1   
2   
...
32   
33  !
34  "
35  #
...
48  0
49  1
50  2
...
65  A
66  B
67  C
...
253 ý
254 þ
255 ÿ

LIKE yüklemini kullanarak ve '0' ila '9' karakter aralığını belirterek rakam karakterleri bulmak için Sembol sütununda filtre yapabilmeyi bekleyebilirim:

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]';

Şaşırtıcı bir çıktı üretir:

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9
178 ²
179 ³
185 ¹
188 ¼
189 ½
190 ¾

48'den 57'ye kadar kod noktaları kümesi beklediğimdir. Beni şaşırtan şey, üst simgeler ve kesirler için sembollerin de sonuç kümesine dahil edilmesidir!

Üsleri ve kesirleri sayı olarak düşünmek için matematiksel bir neden olabilir, ancak onlara rakam demek yanlış görünüyor.

İkili harmanlamayı geçici çözüm olarak kullanma

Beklediğim sonucu elde etmek için, karşılık gelen ikili harmanlama Latin1_General_BIN zorlayabilir anlıyorum:

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0-9]' COLLATE Latin1_General_BIN;

Sonuç kümesi yalnızca 48 ile 57 arasındaki kod noktalarını içerir:

CodePoint   Symbol
48  0
49  1
50  2
51  3
52  4
53  5
54  6
55  7
56  8
57  9

Yanıtlar:


22

[0-9] yalnızca rakamlarla eşleşecek şekilde tanımlanmış bir tür normal ifade değildir.

Bir LIKEkalıptaki herhangi bir aralık, harmanlama sıralama düzenine göre başlangıç ​​ve bitiş karakterleri arasındaki karakterlerle eşleşir.

SELECT CodePoint,
       Symbol,
       RANK() OVER (ORDER BY Symbol COLLATE Latin1_General_CI_AS) AS Rnk
FROM   #CodePage
WHERE  Symbol LIKE '[0-9]' COLLATE Latin1_General_CI_AS
ORDER  BY Symbol COLLATE Latin1_General_CI_AS 

İadeler

CodePoint            Symbol Rnk
-------------------- ------ --------------------
48                   0      1
188                  ¼      2
189                  ½      3
190                  ¾      4
185                  ¹      5
49                   1      5
50                   2      7
178                  ²      7
179                  ³      9
51                   3      9
52                   4      11
53                   5      12
54                   6      13
55                   7      14
56                   8      15
57                   9      16

Böylece bu sonuçları elde edersiniz, çünkü varsayılan harmanlama altında bu karakterler 0önce ancak önce sıralanır 9.

Görünüşe göre harmanlama, 0ve arasındaki kesirler doğru sırada olacak şekilde onları matematiksel olarak sıralamak için tanımlanmış gibi görünüyor 1.

Bir aralık yerine bir küme de kullanabilirsiniz. 2Eşleşmeyi önlemek için ²bir CSharmanlama gerekir

SELECT CodePoint, Symbol
FROM #CodePage
WHERE Symbol LIKE '[0123456789]' COLLATE Latin1_General_CS_AS

6

Latin1, kod sayfası 1252'dir, burada 178 'SUPERSCRIPT TWO' dır . Bu bir Unicode üst simge : üst simge olarak "2" karakteri . Unicode Teknik Standardı # 10'a göre, 2 ile eşit karşılaştırmalıdır, bkz. 8.1 Harmanlama Katlaması :

Tam genişlik ve üst simge karakterleri gibi uyumluluk (üçüncül) eşdeğerleri temsili karakterlerle eşleme

Üst simge 2, 2'den farklı karşılaştırırsa hata olurdu! 'Ancak sütunum Unicode değil' demeden önce, emin olun: MSDN'e göre (bkz. Windows Harmanlama) tüm dize karşılaştırma ve sıralama, disk üzerinde temsil CHAR olsa bile Unicode kurallarına göre yapılır.

Örneğinizdeki diğer karakterlere gelince, beğen VULGAR FRACTION ONE QUARTERve benzerleri herhangi bir sayıya eşit değildir, ancak Mark'ın gösterdiği gibi, 0 ile 9 arasında düzgün bir şekilde sıralanırlar.

Ve elbette, kod sayfasını değiştirirseniz farklı sonuçlar elde edersiniz. Örneğin. ile Greek_CS_AS( kod sayfası 1253 ) kod 178, 179 ve 189 ile karakterleri tanınacak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.