11

2 つのアプリケーション間で共有される sql-server 2010 データベースがあります。1 つのアプリケーションは私たちが管理しており、もう 1 つのアプリケーションは最初にデータベースを作成したサードパーティのアプリです。私たちのアプリは、サードパーティのウェブメール アプリの上に構築された CRM です。

データベースには varchar 列が含まれており、latin-1 でエンコードされています。サードパーティのアプリは php で記述されており、データを正しくエンコードすることを気にしないため、utf-8 でエンコードされたバイトを varchar 列に詰め込み、そこでラテン 1 として解釈され、ゴミのように見えます。

当社の CRM アプリは .Net で作成されており、データベースの照合順序がメモリ内の文字列のエンコードと異なることを自動的に検出します。そのため、.Net がデータベースに書き込むと、データベースのエンコードに一致するようにバイトが変換されます。

そのため...アプリからデータベースに書き込まれたデータはデータベースで正しく見えますが、サードパーティのアプリからのデータはそうではありません。

アプリがFirstName = Célineを書き込むと、データベースにCélineとして保存されます

ウェブメール アプリが FirstName = Céline と書き込むと、DB に Céline として保存されます。

CRM アプリは、いずれかのシステムで作成された連絡先を表示する必要があります。そのため、エンコードが不十分な文字列であることを示すフラグ付き文字を探して変換する EncodingSniffer クラスを作成しています。

現在私は持っています:

プライベート静的文字列[] _flagedChars = 新しい文字列[] {
            「エ」
        };

これは Céline を Céline として表示するのに最適ですが、リストに追加する必要があります。

utf-8 特殊文字が iso-8859-1 として解釈される可能性のあるすべての方法を取得するためのリソースを知っている人はいますか?

ありがとう

明確化: 私は.Netで働いているので。文字列は、データベースからメモリにロードされると、Unicode UTF-16 に変換されます。したがって、データベースで正しくエンコードされているかどうかに関係なく。現在は UTF16 バイトとして表されます。これらのUTF-16バイトを分析し、utf-8バイトがiso-8859-1データベースに詰め込まれているためにそれらが台無しになっているかどうかを判断できる必要があります....泥のように明確ですか?

これが私がこれまでに持っているものです。ほとんどの誤ってエンコードされた文字の表示はクリーンアップされましたが、たとえば É にはまだ問題があります。Éric は Web メールによって Éric としてデータベースに保存されますが、不適切なエンコードを検出して元に戻すと、�? として表示されます。 ric 2500 の連絡先を持っているユーザーを見ると、そのうちの数百はエンコードの問題があり、正しく表示されていないのは É だけです...

public static Regex CreateRegex()
    {
        string specials = "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö";

        List<string> flags = new List<string>();
        foreach (char c in specials)
        {
            string interpretedAsLatin1 = Encoding.GetEncoding("iso-8859-1").GetString(Encoding.UTF8.GetBytes(c.ToString())).Trim();//take the specials, treat them as utf-8, interpret them as latin-1
            if (interpretedAsLatin1.Length > 0)//utf-8 chars made up of 2 bytes, interpreted as two single byte latin-1 chars.
                flags.Add(interpretedAsLatin1);
        }

        string regex = string.Empty;
        foreach (string s in flags)
        {
            if (regex.Length > 0)
                regex += '|';
            regex += s;
        }
        return new Regex("(" + regex + ")");
    }

    public static string CheckUTF(string data)
    {
        Match match = CreateRegex().Match(data);
        if (match.Success)
            return Encoding.UTF8.GetString(Encoding.GetEncoding("iso-8859-1").GetBytes(data));//from iso-8859-1 (latin-1) to utf-8
        else
            return data;
    }

つまり: É は 195'Ã',8240'‰' に変換されます。

4

2 に答える 2

1

おそらく、バイト文字列を UTF-8 としてデコードしてみてください。エラーが発生した場合は、代わりに ISO-8859-1 であると想定してください。

ISO-8859-1 としてエンコードされたテキストが有効な UTF-8 になることはめったにありません...実際に ASCII のみを含む ISO-8859-1 でない限り、その場合は問題ありませんもちろん、すべて。したがって、この方法はかなり堅牢です。

実際の言語でどの文字が他の文字よりも頻繁に出現するかを無視して、ここでは、各文字が同じ頻度で出現すると仮定する単純な分析を行います。有効な ISO-8859-1 を UTF-8 と間違えて文字化けする頻度を調べてみましょう。また、C1 制御文字 (U+0080 から U+009F) は発生しないと仮定します。

バイト文字列内の任意のバイト。バイトが文字列の末尾に近い場合、一部のバイト シーケンスは有効な UTF-8 として十分な長さがないことがわかっているため、不正な形式の UTF-8 を検出する可能性がさらに高くなります。ただし、バイトが文字列の末尾近くにないと仮定すると、次のようになります。

  • p(ASCII としてデコードされたバイト) = 0.57。これは、文字列が ASCII、ISO-8859-1、または UTF-8 であるかどうかに関する情報を提供しません。
  • このバイトが 0x80 から 0xc1 または 0xf8 から 0xff の場合、UTF-8 ではないため、それを検出します。p=0.33
  • この最初のバイトが 0xc2 から 0xdf (p=0.11) の場合、有効な UTF-8 である可能性がありますが、その後に 0x80 から 0xbf の間の値を持つバイトが続く場合に限ります。次のバイトがその範囲にない確率は、192/224 = 0.86 です。したがって、ここで UTF-8 が失敗する確率は 0.09 です。
  • 最初のバイトが 0xe0 から 0xef までの場合、有効な UTF-8 である可能性がありますが、その後に 2 つの継続バイトが続く場合に限ります。したがって、不正な UTF-8 を検出する確率は (16/224)*(1-(0.14*0.14)) = 0.07 です。
  • 0xf0 から 0xf7 までと同様に、確率は (8/224)*(1-(0.14*0.14*0.14)) = 0.04 です。

長い文字列の各バイトで、不正な UTF-8 を検出する確率は 0.33+0.09+0.07+0.04 = 0.53 です。

したがって、長い文字列の場合、ISO-8859-1 が UTF-8 デコーダーを静かに通過する確率は非常に小さく、文字が追加されるたびに約半分になります!

もちろん、この分析はランダムな ISO-8859-1 文字を想定しています。実際には、誤検出率はそれほど良くはありませんが (ほとんどの場合、実際のテキストのほとんどのバイトが実際には ASCII であるという事実が原因です)、それでも非常に良好です。

于 2012-05-07T16:28:20.900 に答える