6

我收到了这个数据库,里面有法文的人名和数据,这意味着,使用诸如 é、è、ö、û 等字符。大约 3000 个条目。

显然,里面的数据有时使用 utf8_encode() 编码,有时没有。这会导致输出混乱:在某些地方,字符显示得很好,而在其他地方则没有。

起初我试图追踪 UI 中出现这些问题的每个地方,并在必要时使用 utf8_decode() ,但这确实不是一个可行的解决方案。

我做了一些测试,首先没有理由使用 utf8_encode,所以我宁愿删除所有这些,只在任何地方使用 UTF8 - 在浏览器、中间件和数据库级别。所以我需要清理数据库,通过清理后的版本转换所有错误编码的数据。

问题:是否有可能在 php 中创建一个函数来检查 utf8 字符串是否正确编码(没有 utf8_encode)或没有(使用 utf8_encode),如果是,将其转换回其原始状态?

换句话说:我想知道如何将已经是 utf8_encode() 的 utf8 内容检测到不是 utf8_encode()d 的 utf8 内容。

**更新:示例**

这是一个很好的示例:您获取一个充满特殊字符的字符串,并获取该字符串的副本并使用 utf8_encode() 它。我梦寐以求的函数需要两个字符串,第一个字符串保持不变,第二个字符串现在与字符串一个相同。

我试过这个:

$loc_fr = setlocale(LC_ALL, 'fr_BE.UTF8','fr_BE@euro', 'fr_BE', 'fr', 'fra', 'fr_FR');
$str1= "éèöûêïà ";
$str2 = utf8_encode($str1);

function convert_charset($str) {
    $charset=  mb_detect_encoding($str);
    if( $charset=="UTF-8" ) {
        return utf8_decode($str);
    }
    else {
        return $str;
    }
}
function correctString($str) {
    echo "\nbefore: $str";
    $str= convert_charset($str);
    echo "\nafter: $str"; 
}

correctString($str1);
echo('<hr/>'."\n");
correctString($str2);

这给了我:

before: éèöûêïà after: ������� 
before: éèöûêïà  after: éèöûêïà 

谢谢,

亚历克斯

4

5 回答 5

6

从您当前正在查看的字符编码镜头(这取决于您的文本编辑器的默认值、浏览器标题、数据库配置等)以及数据经历了哪些字符编码转换的问题中,尚不完全清楚。例如,可能通过调整数据库配置,一切都会得到纠正,这比对数据进行零碎更改要好得多。

看起来可能是utf8双编码的问题,如果是这样的话,原始数据和损坏的数据都将在utf8中,因此编码检测不会为您提供所需的信息。这种情况下的方法需要假设哪些字符可以合理地出现在您的数据中:就 PHP 和 Mysql 而言,“é”是完全合法的 utf8,因此您必须根据您对数据及其作者认为它必须被破坏。如果您只是一名技术人员,这些都是有风险的假设。幸运的是,如果您知道数据是法语的并且只有 3000 条记录,那么做出这些假设可能是可以的。

下面是一个脚本,您可以首先调整它来检查您的数据,然后更正它,最后再次检查它。它所做的只是将字符串处理为 utf8,将其分解为字符,并将这些字符与预期的法语字符的白名单进行比较。如果字符串不是 utf8 格式或包含法语中通常不期望的字符,则表示存在问题,例如:

PROBABLY OK     Côte d'Azur
HAS NON-WHITELISTED CHAR        Côte d'Azur    195,180 ô
NON-UTF8        C�e d'Azur

这是脚本,您需要从http://hsivonen.iki.fi/php-utf8/下载相关的 unicode 函数

<?php

// Download from http://hsivonen.iki.fi/php-utf8/
require "php-utf8/utf8.inc";

$my_french_whitelist = array_merge(
  range(0,127), // throw in all the lower ASCII chars
  array(
    0xE8, // small e-grave
    0xE9, // small e-acute
    0xF4, // small o-circumflex
    //... Will need to add other accented chars,
    // Euro sign, and whatever other chars
    // are normally expected in the data.
  )
);

// NB, whether this string literal is in utf8
// depends on the encoding of the text editor
// used to write the code
$str1 = "Côte d'Azur";
$test_data = array(
  $str1,
  utf8_encode($str1),
  utf8_decode($str1),
);

foreach($test_data as $str){
  $questionable_chars = non_whitelisted(
    $my_french_whitelist,
    $str
  );
  if($questionable_chars===true){
    p("NON-UTF8", $str);
  }else if ($questionable_chars){
    p(
      "HAS NON-WHITELISTED CHAR",
      $str,
      implode(",", $questionable_chars),
      unicodeToUtf8($questionable_chars)
    );
  }else{
    p("PROBABLY OK", $str);
  }
}

function non_whitelisted($whitelist, $utf8_str){
  $codepoints = utf8ToUnicode($utf8_str);
  if($codepoints===false){ // has non-utf8 char
    return true;
  }
  return array_diff(
    array_unique($codepoints),
    $whitelist
  );
}


function p(){
  $args = func_get_args();
  echo implode("\t", $args), "\n";
}
于 2009-10-02T00:02:30.173 回答
2

我认为您可能会采用更多的编译方法。几周前我收到了一个保加利亚语数据库,该数据库在数据库中动态编码,但是当将它移动到另一个数据库时,我得到了时髦???

我解决这个问题的方法是转储数据库,将数据库设置为 utf8 排序规则,然后将数据作为二进制文件导入。这将所有内容自动转换为 utf8 并且不再给我???。

这是在 MySQL

于 2009-10-02T15:42:00.537 回答
2

当您连接到数据库时,请记住始终使用 mysql_set_charset('utf8', $db_connection);

它会解决一切,它解决了我所有的问题。

看到这个: http: //phpanswer.com/store-french-characters-into-mysql-db-and-display/

于 2010-08-15T02:11:05.720 回答
0

正如您所说,您的数据有时使用 转换utf8_encode,您的数据使用 UTF-8 或 ISO 8859-1 编码(因为utf8_encode从 ISO 8859-1 转换为 UTF-8)。并且由于 UTF-8 使用从 1100001x 开始的两个字节对从 128 到 255 的字符进行编码,因此您只需测试您的数据是否是有效的 UTF-8,如果不是,则将其转换。

因此,如果它已经是 UTF-8(请参阅几个is_utf8函数),请扫描所有数据,如果它utf8_encode不是 UTF-8,则使用它。

于 2009-10-01T12:06:21.530 回答
0

我的问题是,不知何故,我以纯格式或 utf8 编码的方式将这些 à,é,ê 之类的数据库字符放入了数据库中。经过调查,我得出的结论是某些浏览器(我不知道 IE 或 FF 或其他)正在对提交的输入数据进行编码,因为没有有意添加 utf8 编码来处理提交表单。因此,如果我使用 utf8_encode 读取数据,我将更改其他纯字符,反之亦然。

我的解决方案,在我研究了上面给出的解决方案之后: 1. 我用 charset utf8 创建了一个新数据库 2. 在我将 sql 转储文件中 CREATE TABLE 语句的字符集定义从 Latin.... 更改为 UTF8 之后导入了数据库。3. 从原始数据库导入数据(直到这里可能仅仅改变现有数据库和表上的字符集就足够了,并且只有当原始数据库不是 utf8 时才这样做) 4. 通过替换 utf8 编码的字符直接更新数据库中的内容有简单的格式,比如

UPDATE `clients` SET `name` = REPLACE(`name`,"é",'é' )  WHERE `name` LIKE CONVERT( _latin1 '%é%' USING utf8 ); 
  1. 我放入 db 类(用于 php 代码)这一行以确保它们是 UTF8 通信

    $this->query('SET CHARSET UTF8');

那么,何来更新?(第 4 步)我构建了一个数组,其中包含可能被编码的字符

$special_chars = array(
  'ù','û','ü',
  'ÿ',
  'à','â','ä','å','æ',
  'ç',
  'é','è','ê','ë',
  'ï','î',
  'ô','','ö','ó','ø',
  'ü');

我已经建立了一个包含成对表的数组,应该更新的字段

$where_to_look = array(
    array("table_name" , "field_name"),
        ..... );

比,

    foreach($special_chars as $char)
    {
      foreach($where_to_look as $pair)
      {
        //$table = $pair[0]; $field = $pair[1]
        $sql = "SELECT id , `" . $pair[1] . "` FROM " .$pair[0] . " WHERE `" . $pair[1] . "` LIKE CONVERT( _latin1 '%" . $char . "%' USING utf8 );";

    if($db->num_rows() > 0){
         $sql1 = "UPDATE " . $pair[0] . " SET `" . $pair[1] . "` = REPLACE(`" . $pair[1] . "`,CONVERT( _latin1 '" . $char . "' USING utf8 ),'" . $char . "' )  WHERE `" . $pair[1] . "` LIKE CONVERT( _latin1 '%" . $char . "%' USING utf8 )";
         $db1->query($sql1);
        }
    }
 }

基本思路是利用mysql的编码特性,避免mysql、apache、浏览器和back之间进行编码;注意:我没有可用的 php 函数,如 mb_....

最好的

于 2009-10-23T11:00:10.447 回答