在c / c ++中从字符串中删除无效的utf8

时间:2013-06-26 09:36:27

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

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

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

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

2 个答案:

答案 0 :(得分:1)

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

1)弄清楚实际编码是什么,并从那里重新编码为UTF-8。我认为这个特定的页面是Latin-1(当我用wget抓取它时),但不是所有错误标记的页面都必然。对于它的价值,我在实践中看到的最常见的错误标签是Windows CP-1252,标榜为Latin-1。

2)盲目地删除顶部位设置的所有字符(即,字符值不在0 ... 127范围内),或者假设用?等字符替换真正的编码是一些8位代码页或其他,但你不关心什么。

答案 1 :(得分: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

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