Traduction automatique lors de la conversion d'Unicode en non-Unicode / NVARCHAR en VARCHAR


8

Le point de code Unicode 9619 est un caractère appelé "Ombre sombre": ( http://unicode-table.com/en/search/?q=9619 ).

En utilisant le SQL_Latin1_General_CP1_CI_ASclassement et la page de codes 1252, je m'attendrais à ce que la conversion / conversion de ce caractère Unicode en type de données non Unicode entraîne un point d'interrogation ( ?) car la page de codes 1252 ne semble pas contenir ce caractère et cela semble être SQL Server. comportement lorsque la conversion ne peut pas avoir lieu.

Donc ma question est: pourquoi SQL Server convertit-il ce caractère en un code ASCII 166 qui est "Pipe, barre verticale brisée" ¦:?

SELECT NCHAR(9619), CAST(NCHAR(9619) AS CHAR(1)), ASCII(CAST(NCHAR(9619) AS CHAR(1)))

3
SQL Server utilise ce que cet article appelle la transformation homoglyphique et convertit souvent des caractères qui ne peuvent pas être représentés en quasi équivalents. Telles que la perte de l'accent sur un personnage ou la modification de citations intelligentes en citations simples. Je suis d'accord que cela ne semble pas très proche! Je ne sais pas si ni où ces transformations sont documentées.
Martin Smith

Wow, je n'en avais aucune idée ... bon sang, ça ne semble pas juste ... ce n'est pas le même personnage. Pourquoi pas juste un "... oups, aucun tel caractère trouvé dans cette page de code ..." et échouer la conversion?
Henry Lee

1
Je lis juste cette page et je m'en souviens. Je ne sais pas si SQL Server utilise exactement les mêmes algorithmes "les mieux adaptés".
Martin Smith

1
@MartinSmith concernant le fait de ne pas être sûr des mappages "les mieux adaptés" pour SQL Server, veuillez voir ma réponse ci-dessous car j'ai trouvé ces mappages :-).
Solomon Rutzky

Réponses:


8

Pourquoi SQL convertit-il l'Unicode 9619 en code ASCII 166?

SQL Server n'utilise aucune logique personnalisée spéciale ici; il utilise les services du système d'exploitation standard pour effectuer la conversion.

Plus précisément, le type SQL Server et le service d'expression ( sqlTsEs) appellent la routine du système d'exploitation WideCharToMultiBytedans kernel32.dll. SQL Server définit les paramètres d'entrée de WideCharToMultiBytetelle sorte que la routine effectue une «traduction rapide». C'est plus rapide que de demander qu'un caractère par défaut spécifique soit utilisé en l'absence de traduction directe.

La traduction rapide repose sur la page de code cible pour effectuer un mappage optimal pour tous les caractères sans correspondance, comme mentionné dans le lien fourni par Martin Smith dans un commentaire à la question:

Les stratégies les plus adaptées varient selon les différentes pages de code et ne sont pas documentées en détail.

Lorsque les paramètres d'entrée sont définis pour une traduction rapide, WideCharToMultiByteappelle le service OS GetMBNoDefault( source ). L'inspection de la pile d'appels de SQL Server lors de la conversion spécifiée dans la question le confirme:

Trace de pile SQL Server


7

La conversion des données Unicode vers une page de codes particulière utilise ce que l'on appelle la stratégie de "meilleur ajustement" (comme indiqué dans la réponse de @ Paul et dans le lien que @Martin a noté dans un commentaire sur la question). Selon cette page MSDN pour le codage de caractères dans le .NET Framework :

Le mappage le mieux adapté est le comportement par défaut d'un objet Encoding qui code les données Unicode en données de page de code ...

Mais que sont exactement ces mappages? Cette page MSDN utilisé pour communiquer ce qui suit:

Les stratégies les plus adaptées varient selon les différentes pages de code et ne sont pas documentées en détail.

Cependant, ce n'était pas tout à fait exact. Peut-être que les "stratégies" pour déterminer les mappages ne sont pas exactement documentées. D'accord. Mais, les mappages eux - mêmes sont documentés, mais pas dans les endroits les plus faciles à trouver.

Donc, grâce à Microsoft qui a déplacé la documentation vers GitHub, cette page indique maintenant ce qui suit (parce que je l'ai mise à jour 😸):

Les stratégies les plus adaptées ne sont pas documentées en détail. Cependant, plusieurs pages de codes sont documentées sur le site Web du Consortium Unicode . Veuillez consulter le fichier readme.txt dans ce dossier pour une description de la façon d'interpréter les fichiers de mappage.

Si vous accédez à l'URL suivante, vous verrez une liste de plusieurs fichiers, chacun nommé pour la page de codes à laquelle il mappe les caractères Unicode:

ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WindowsBestFit/

La plupart des fichiers ont été mis à jour pour la dernière fois (ou du moins y ont été placés) le 2006-10-04, et l'un d'eux a été mis à jour le 2012-03-14. La première partie de ces fichiers mappe les codes ASCII dans un point de code Unicode équivalent. Mais la deuxième partie de chaque fichier mappe les caractères Unicode dans leurs "équivalents" ASCII.

J'ai écrit un script de test qui utilise les mappages de la page de code 1252 pour vérifier si SQL Server utilise vraiment ces mappages. Cela peut être déterminé en répondant à ces deux questions:

  1. Pour tous les points de code mappés, SQL Server les convertit-il en mappages spécifiés?
  2. Pour tous les points de code non mappés, SQL Server convertit-il certains d'entre eux en caractères non " ?"?

Le script de test est trop long pour être placé ici, donc je l'ai posté sur Pastebin à:

Mappages Unicode vers la page de codes dans SQL Server

L'exécution du script montrera que la réponse à la première question ci-dessus est "Oui" (ce qui signifie que tous les mappages fournis sont respectés). Cela montrera également que la réponse à la deuxième question est "Non" (ce qui signifie qu'aucun des points de code non mappés ne se transforme en autre chose que le caractère "inconnu"). Par conséquent, ce fichier de mappage est très précis :-).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.