Удалить управляющие символы, но оставить ½ символов и т. Д. - PullRequest
1 голос
/ 28 января 2020

У меня есть хранимая процедура T- SQL, которая возвращает плоский список результатов, используя команду 'for xml' для преобразования в XML.

Иногда возникают проблемы, когда данные от третьей стороны, которая содержит управляющие символы, передается в одно из преобразованных полей varchar.

Я решил эту проблему с помощью 64-й кодировки varchar перед выполнением преобразования:

cast(InvalidText as varbinary) as FixedText

Затем я декодировал это из базы 64 в моем приложении C#.

Это прекрасно работает, за исключением случаев, когда текст содержит символ, такой как ½. После декодирования этих символов они отображаются как *.

Мне нужно отобразить эти символы. Есть ли способ решить обе проблемы?

РЕДАКТИРОВАТЬ: Я пытался указать кодировку UTF-8 при отправке моего XML в мое приложение C#. Это не помогло.

Вот упрощенный пример того, что происходит:

SQL:

select cast('Take ½ of the total' as varbinary) for xml path ('result'), type;

Затем я передаю эту закодированную строку в мое приложение C# .

C#:

using System;
using System.Text;

public class Program
{
    public static void Main()
    {
        var encodedText = "VGFrZSC9IG9mIHRoZSB0b3RhbA=="; // From SQL encoding above

        var decodedText = Encoding.UTF8.GetString(
            Convert.FromBase64String(encodedText));

        Console.WriteLine(decodedText);
    }
}

Вывод на консоль: Взять � от общей суммы

Ручное добавление в начале документа XML дает те же результаты.

1 Ответ

1 голос
/ 28 января 2020

Я не совсем уверен в вашей проблеме, но думаю, что вы копали не в том месте.

SQL -Сервер знает два типа строк для работы:

Пока вы не смешиваете 1- и 2-байтовые строки в бинарных подходах это работает довольно хорошо.

Попробуйте это:

SELECT 'A½B' AS UsingASCII
      ,CAST('A½B' AS VARBINARY(MAX)) AS UsingASCIIasBinary
      ,N'A½B' AS UsingUCS2
      ,CAST(N'A½B' AS VARBINARY(MAX)) AS UsingUCS2asBinary
FOR XML PATH('')

возвращает

Text    binary          base64
A½B     0x41BD42        Qb1C    
A½B     0x4100BD004200  QQC9AEIA  

Вы можете увидеть HEX-коды 41, BD и 42 для три символа и 00, чтобы сделать его 2-байтовым UCS2 .

Кодовые точки 41 и 42 - это "A" и "B", в то время как кодовая точка BD обозначает ваш специальный символ.

SQL -Процесс сервера не является чудом ...

В SQL -Сервер оператор FOR XML вернет нативный XML, формат вывода по умолчанию NVARCHAR(MAX). Конечно, это не будет UTF8.

Переконвертировать base64 из примера выше

DECLARE @xml XML=
N'<binaryASCII>Qb1C</binaryASCII>
  <binaryUCS2>QQC9AEIA</binaryUCS2>';

SELECT @xml.value('(/binaryASCII)[1]','varbinary(max)')
      ,CAST(@xml.value('(/binaryASCII)[1]','varbinary(max)') AS VARCHAR(MAX)) ReconvertedFromASCII
      ,@xml.value('(/binaryUCS2)[1]','varbinary(max)')
      ,CAST(@xml.value('(/binaryUCS2)[1]','varbinary(max)')  AS NVARCHAR(MAX)) ReconvertedFromUCS2;

Для чтения base64 в T- SQL требуется небольшой XML -хак:

Ваш пример base64:

SELECT CAST(CAST('VGFrZSC9IG9mIHRoZSB0b3RhbA==' AS XML)
                .value('.','varbinary(max)') AS VARCHAR(MAX));

Моя система правильно возвращает символ "half". Это позволяет мне предположить, что ваше стандартное сопоставление сопоставляет другой / без символа с этой кодовой точкой.

Попробуйте выяснить ваше сопоставление по умолчанию и проверить параметры сопоставления соответствующих столбцов и прочитать о COLLATE.

...