如何确保在C程序中将包含uft8字符的字符串正确写入mysql?

uubf1zoe  于 5个月前  发布在  Mysql
关注(0)|答案(1)|浏览(72)

我试图在MariaDB数据库中插入一个字符串,其中包含一个大于128的Unicode字符,即177,±

wchar_t wcs = L"INSERT INTO text(drawing, eID, txt) VALUES(9,14063,'\261\065\061\067\071')";

字符串
使用wctombs

int ret;
ret = wctombs(querybuffer, wcs, 60);


ret是-1,这显然意味着有一个宽字符不对应于有效的多字节字符。
我已经根据John Bollinger的建议修改了我的代码(非常感谢):

while(txt[i])
{
  c=cleaveMControl(txt,&i,j);
  if(c){
    if(c<128)
      query[j++]=c;
    else{
      query[j++]=92;
      query[j++]=92;
      sprintf(query+j,"u00%x",c);
      j=strlen(query);
    }
  }
}
query[j++]=39;
query[j++]=41;
query[j++]=59;
query[j]=0;
mysql_query(sqlconnect,query);


这产生:

MariaDB [D8]> select * from text where eID=14063;
+---------+-------+------------+
| drawing | eID   | txt        |
+----------+-------+------------+
|       9 | 14063 | \u00b15179 |
+---------+-------+------------+


我期待看到“± 5179”。

2j4z5cfb

2j4z5cfb1#

如何确保在C程序中将包含uft 8字符的字符串正确写入mysql?
开始,这是错误的:

wchar_t wcs=L"INSERT INTO text(drawing, eID, txt) VALUES(9,14063,'\261\065\061\067\071')"

字符串
你的编译器应该警告你不要在没有强制转换的情况下将指针赋值给一个整数(而且是一个更窄的整数)。它也应该在这里抱怨:

ret=wctombs(querybuffer,wcs,60);


..
wcs的这种定义更有可能起作用:

const wchar_t *wcs = L"INSERT INTO text(drawing, eID, txt) VALUES(9,14063,'\261\065\061\067\071')";


最主要的是,你需要声明wcs作为一个指针,而不是一个单独的wchar_t。添加const提供了一些保护,防止意外尝试修改内容,这是你不能做的。
但如果你能假设至少是C11,那么

  • 您可以通过使用UTF-8字符串字面量,以可移植的方式定义在内存中通过UTF-8编码的字符串。
  • 在任何字符串文本中,您都可以使用“通用字符名”来通过字符Unicode代码点值引用字符。

把这些放在一起,在C11或更高版本中,你可以说:

const char *s = u8"INSERT INTO text(drawing, eID, txt) VALUES(9,14063,'\u00b1" u8"5171')";


来获取所需的UTF-8编码字节,而无需考虑源和执行字符集。
顺便说一下,没有必要像我一样将其分为两个字面量,但这样做有助于澄清通用字符名称\u00b1不会继续到字符串的后续数字。(注意:也有8位通用字符名称,但它们以\U而不是\u开头)。
如果你不能假设至少是C11,那么你最好还是跳过宽字符串字面量,而不是直接插入UTF-8编码的单个字符:

const char *s = "INSERT INTO text(drawing, eID, txt) VALUES(9,14063,'\302\261" "5171')";


这确实依赖于对执行基本字符集的字符进行ASCII(和UTF8)兼容的编码,但这是一个相对安全的选择,并且与宽字符串变体工作所需的要求相比,这是一个较弱的要求。

相关问题