【问题标题】:Strip invalid utf8 from string in c/c++从 C/C++ 中的字符串中去除无效的 utf8
【发布时间】:2013-06-26 09:36:27
【问题描述】:

我有 curl 从“view-source:http://vvs24.com/component/contact/1.html”等网页生成的字符串 utf-8 字符无效。

在我的例子中 'advsearch': ' Avansert s�k', = ø 但使用 utf8 以外的其他编码。

如何更正此错误,因为我需要将字符串插入 mysql(使用 C 库)并且它会在无效字符处被修剪,即使在 mysql_real_escape() 之后也是如此,因为它是 @987654322 @。

【问题讨论】:

    标签: c++ mysql c utf-8 mysql-connector


    【解决方案1】:

    根据Steve Jessop 所说的,我最终制作了一个可以纠正最常见错误并删除其余错误的函数。

    #include<string>
    #include<iostream>
    using namespace std;
    
    string correct_non_utf_8(string *str)
    {
        int i,f_size=str->size();
        unsigned char c,c2,c3,c4;
        string to;
        to.reserve(f_size);
    
        for(i=0 ; i<f_size ; i++){
            c=(unsigned char)(*str)[i];
            if(c<32){//control char
                if(c==9 || c==10 || c==13){//allow only \t \n \r
                    to.append(1,c);
                }
                continue;
            }else if(c<127){//normal ASCII
                to.append(1,c);
                continue;
            }else if(c<160){//control char (nothing should be defined here either ASCI, ISO_8859-1 or UTF8, so skipping)
                if(c2==128){//fix microsoft mess, add euro
                    to.append(1,226);
                    to.append(1,130);
                    to.append(1,172);
                }
                if(c2==133){//fix IBM mess, add NEL = \n\r
                    to.append(1,10);
                    to.append(1,13);
                }
                continue;
            }else if(c<192){//invalid for UTF8, converting ASCII
                to.append(1,(unsigned char)194);
                to.append(1,c);
                continue;
            }else if(c<194){//invalid for UTF8, converting ASCII
                to.append(1,(unsigned char)195);
                to.append(1,c-64);
                continue;
            }else if(c<224 && i+1<f_size){//possibly 2byte UTF8
                c2=(unsigned char)(*str)[i+1];
                if(c2>127 && c2<192){//valid 2byte UTF8
                    if(c==194 && c2<160){//control char, skipping
                        ;
                    }else{
                        to.append(1,c);
                        to.append(1,c2);
                    }
                    i++;
                    continue;
                }
            }else if(c<240 && i+2<f_size){//possibly 3byte UTF8
                c2=(unsigned char)(*str)[i+1];
                c3=(unsigned char)(*str)[i+2];
                if(c2>127 && c2<192 && c3>127 && c3<192){//valid 3byte UTF8
                    to.append(1,c);
                    to.append(1,c2);
                    to.append(1,c3);
                    i+=2;
                    continue;
                }
            }else if(c<245 && i+3<f_size){//possibly 4byte UTF8
                c2=(unsigned char)(*str)[i+1];
                c3=(unsigned char)(*str)[i+2];
                c4=(unsigned char)(*str)[i+3];
                if(c2>127 && c2<192 && c3>127 && c3<192 && c4>127 && c4<192){//valid 4byte UTF8
                    to.append(1,c);
                    to.append(1,c2);
                    to.append(1,c3);
                    to.append(1,c4);
                    i+=3;
                    continue;
                }
            }
            //invalid UTF8, converting ASCII (c>245 || string too short for multi-byte))
            to.append(1,(unsigned char)195);
            to.append(1,c-64);
        }
        return to;
    }
    

    参考:wikipediautf8-chartable.de

    更新 1

    • 添加了边界检查并略有改进
    • 仍在运行一些测试(因此请谨慎使用)

    【讨论】:

    • 读取多个字符时需要检查字符串边界
    • @pogorskiy 我猜你指的是(unsigned char)(*str)[i+1],是的,你是对的。我会更新的。谢谢
    【解决方案2】:

    看起来好像服务器错误地将某些其他编码标记为 UTF-8。所以你有(至少)两个选择:

    1) 找出真正的编码是什么,然后将其重新编码为 UTF-8。我认为这个特定的页面是 Latin-1(当我用 wget 抓取它时),但并非所有贴错标签的页面都必须如此。无论如何,我在实践中看到的最常见的错误标签是 Windows CP-1252 被宣传为 Latin-1。

    2) 在假设真正的编码是一些 8 位代码页或其他,但你不在乎。

    【讨论】:

    • 我问过类似here 的问题来检测正确的字符集。我已经完成了这些程序,但有些页面粘贴了 utf8 和其他一些字符,所以我选择看起来最好的。
    • 所以方法 2 是做一个for(i=0;i&lt;str.size();i++){if((int)str[i]&gt;127 &amp;&amp; (int)str[i]&lt;0) str[i] = '?';} ?
    • 不起作用,例如 utf8 中的 ø 有代码 (-61 , -72 ) 所以我也去掉这些并添加 2 个问号
    猜你喜欢
    • 2018-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    • 1970-01-01
    • 2011-05-22
    • 2012-07-11
    相关资源
    最近更新 更多