【问题标题】:json_encode() non utf-8 strings?json_encode() 非 utf-8 字符串?
【发布时间】:2011-09-30 04:57:24
【问题描述】:

所以我有一个字符串数组,所有字符串都使用系统默认的 ANSI 编码,并且是从 SQL 数据库中提取的。所以有 256 种不同的可能字符字节值(单字节编码)。
有没有办法让json_encode() 工作并显示这些字符,而不必在我的所有字符串上使用utf8_encode() 并以\u0082 之类的东西结束?

或者这是 JSON 的标准?

【问题讨论】:

    标签: php json encoding utf-8 ansi


    【解决方案1】:

    有没有办法让 json_encode() 工作并显示这些字符,而不必在我的所有字符串上使用 utf8_encode() 并以“\u0082”之类的东西结束?

    如果你有一个 ANSI 编码的字符串,使用utf8_encode()错误 函数来处理这个问题。您需要先将其从 ANSI 正确转换为 UTF-8。这肯定会减少 json 输出中像 \u0082 这样的 Unicode 转义序列的数量,但从技术上讲,这些序列 are valid for json,你不必害怕它们。

    使用 PHP 将 ANSI 转换为 UTF-8

    json_encode 适用于UTF-8 编码字符串。如果您需要从ANSI 编码的字符串成功创建有效的json,则需要先将其重新编码/转换为UTF-8。然后json_encode 将按文档说明工作。

    要将编码从ANSI(更准确地说,我假设您有一个Windows-1252 编码字符串,它很流行但被错误地称为ANSI)转换为UTF-8,您可以使用mb_convert_encoding()功能:

    $str = mb_convert_encoding($str, "UTF-8", "Windows-1252");
    

    PHP 中另一个可以转换字符串的编码/字符集的函数称为iconv,基于libiconv。你也可以使用它:

    $str = iconv("CP1252", "UTF-8", $str);
    

    关于 utf8_encode() 的注意事项

    utf8_encode() 仅适用于 Latin-1,不适用于 ANSI。因此,当您通过该函数运行它时,您将破坏该字符串中的部分字符。


    相关:What is ANSI format?


    如需对json_encode() 返回的内容进行更细粒度的控制,请参阅list of predifined constants(取决于 PHP 版本,包括 PHP 5.4,一些常量未记录,仅在源代码中可用)。

    更改数组的编码/迭代(PDO 注释)

    正如您在评论中写道,将函数应用于数组时遇到问题,这里有一些代码示例。在使用json_encode 之前,总是需要首先更改编码。这只是一个标准的数组操作,对于 pdo::fetch()foreach 迭代这样更简单的情况:

    while($row = $q->fetch(PDO::FETCH_ASSOC))
    {
      foreach($row as &$value)
      {
        $value = mb_convert_encoding($value, "UTF-8", "Windows-1252");
      }
      unset($value); # safety: remove reference
      $items[] = array_map('utf8_encode', $row );
    }
    

    【讨论】:

    • 这几乎可以回答我的问题。但是,当我确实按照您所说的那样使用 mb_convert_encoding() 时, json_encode() 仍然只是给我包含奇数字符的字符串的空值。但是,如果我做这样的事情,(还要注意这个带有值的数组来自 PDOStatement->fetchAll())。但是对于这种方法,我发现我正在遍历每个项目,而不是仅仅抓取一个数组,并且字符显示为转义,例如 \u0082。等等 "while($row = $q->fetch(PDO::FETCH_ASSOC)) { $items[] = array_map(utf8_encode, $row); }" 我应该使用这个还是做不同的事情?
    • 实际上,mb_convert_encoding() 确实有效。我的错。现在可以循环遍历从 PDOStatement->fetchAll() 获取的数组,或者遍历并单独获取每个项目,并使用我在其他评论中添加的代码。 :\ (顺便说一下,这个数组中的每个项目都有几个字符串)
    • @Josh,我已经编辑了这个问题。我不确定我是否完全理解您的问题,我添加了一个示例,您可以如何更改从 PDO 获得的 $row 数组中每个元素的编码。
    • 我明白为什么会这样,但是 /MAN/ 这很烦人 :D 感谢@hakre 的解释
    【解决方案2】:

    JSON 标准ENFORCES Unicode 编码。来自RFC4627

    3.  Encoding
    
       JSON text SHALL be encoded in Unicode.  The default encoding is
       UTF-8.
    
       Since the first two characters of a JSON text will always be ASCII
       characters [RFC0020], it is possible to determine whether an octet
       stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
       at the pattern of nulls in the first four octets.
    
               00 00 00 xx  UTF-32BE
               00 xx 00 xx  UTF-16BE
               xx 00 00 00  UTF-32LE
               xx 00 xx 00  UTF-16LE
               xx xx xx xx  UTF-8
    

    因此,严格来说,ANSI 编码的 JSON 不是有效的 JSON;这就是 PHP 在使用 json_encode() 时强制执行 unicode 编码的原因。

    至于“默认 ANSI”,我很确定您的字符串是在 Windows-1252 中编码的。它被错误地称为 ANSI。

    【讨论】:

      【解决方案3】:
      <?php
      $array = array('first word' => array('Слово','Кириллица'),'second word' => 'Кириллица','last word' => 'Кириллица');
      echo json_encode($array);
      /*
      return {"first word":["\u0421\u043b\u043e\u0432\u043e","\u041a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430"],"second word":"\u041a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430","last word":"\u041a\u0438\u0440\u0438\u043b\u043b\u0438\u0446\u0430"}
      */
      echo json_encode($array,256);
      /*
      return {"first word":["Слово","Кириллица"],"second word":"Кириллица","last word":"Кириллица"}
      */
      ?>
      

      JSON_UNESCAPED_UNICODE(整数) 对多字节 Unicode 字符进行逐字编码(默认转义为 \uXXXX)。自 PHP 5.4.0 起可用。

      http://php.net/manual/en/json.constants.php#constant.json-unescaped-unicode

      【讨论】:

      • 对我来说这行得通:json_encode($obj, JSON_UNESCAPED_UNICODE);
      【解决方案4】:

      我找到了以下类似问题的答案:嵌套数组不是 utf-8 编码的,我必须进行 json 编码:

      $inputArray = array(
          'a'=>'First item - à',
          'c'=>'Third item - é'
      );
      $inputArray['b']= array (
                'a'=>'First subitem - ù',
                'b'=>'Second subitem - ì'
          );
       if (!function_exists('recursive_utf8')) {
        function recursive_utf8 ($data) {
           if (!is_array($data)) {
              return utf8_encode($data);
           }
           $result = array();
           foreach ($data as $index=>$item) {
              if (is_array($item)) {
                 $result[$index] = array();
                 foreach($item as $key=>$value) {
                    $result[$index][$key] = recursive_utf8($value);
                 }
              }
              else if (is_object($item)) {
                 $result[$index] = array();
                 foreach(get_object_vars($item) as $key=>$value) {
                    $result[$index][$key] = recursive_utf8($value);   
                 }
              } 
              else {
                 $result[$index] = recursive_utf8($item);
              }
           }
           return $result; 
         }
      }
      $outputArray =  json_encode(array_map('recursive_utf8', $inputArray ));
      

      【讨论】:

        【解决方案5】:
        json_encode($str,JSON_HEX_TAG|JSON_HEX_AMP|JSON_HEX_APOS|JSON_HEX_QUOT);
        

        这会将基于 Windows 的 ANSI 转换为 utf-8,并且不会再出现错误。

        【讨论】:

        • 这些标志都与编码 JSON_HEX_TAG 无关:处理“”; JSON_HEX_AMP:处理“&”; JSON_HEX_APOS:处理单引号“'”; JSON_HEX_QUOT:处理双引号'"';
        【解决方案6】:

        改用这个:

        <?php 
        //$return_arr = the array of data to json encode 
        //$out = the output of the function 
        //don't forget to escape the data before use it! 
        
        $out = '["' . implode('","', $return_arr) . '"]'; 
        ?>
        

        json_encode php manual 的 cmets 复制。始终阅读 cmets。它们很有用。

        【讨论】:

        • 这没什么用,因为它根本不处理编码。
        猜你喜欢
        • 2017-06-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-16
        • 1970-01-01
        相关资源
        最近更新 更多