Ký tự Unicode trong chuỗi PHP


164

Câu hỏi này có vẻ đơn giản, nhưng tôi không thể tìm được câu trả lời.

PHP tương đương với dòng mã C # sau đây là gì?

string str = "\u1000";

Mẫu này tạo một chuỗi có một ký tự Unicode duy nhất có "giá trị số Unicode" là 1000 ở dạng thập lục phân (4096 theo số thập phân).

Đó là, trong PHP, làm cách nào tôi có thể tạo một chuỗi với một ký tự Unicode duy nhất có "giá trị số Unicode" được biết đến?



4
@diEcho: chỉ dành cho các ký tự Unicode phù hợp, nhưng OP muốn tạo cho các ký tự đó.
Stefan Gehrig


Câu trả lời:


178

Bởi vì JSON trực tiếp hỗ trợ \uxxxxcú pháp, điều đầu tiên tôi nghĩ đến là:

$unicodeChar = '\u1000';
echo json_decode('"'.$unicodeChar.'"');

Một lựa chọn khác là sử dụng mb_convert_encoding()

echo mb_convert_encoding('က', 'UTF-8', 'HTML-ENTITIES');

hoặc sử dụng ánh xạ trực tiếp giữa UTF-16BE (endian lớn) và bảng mã Unicode:

echo mb_convert_encoding("\x10\x00", 'UTF-8', 'UTF-16BE');

9
JSON không phải là JavaScript.
Gumbo

4
@Gumbo: Tôi biết điều đó nhưng nó không tạo ra sự khác biệt nào ở đây. Javascript cũng như JSON hỗ trợ \uxxxxcú pháp Unicode để bạn có thể sử dụng json_decodeđể làm việc trên biểu diễn chuỗi JSON được tạo một cách giả tạo. Tôi đã thay đổi từ ngữ mặc dù để làm rõ điều đó.
Stefan Gehrig

3
Ok, vì vậy, công thức nghiêm ngặt của một câu trả lời cho câu hỏi của tôi là: $ str = json_decode ('"\ u1000"'); Cảm ơn bạn.
Telaclavo

Tôi đã thử trong echo json_decode('\u201B');đó đề cập đến một trích dẫn được hoàn nguyên duy nhất Tuy nhiên nó không hoạt động, có nghĩa là không có đầu ra (ngay cả khi được dẫn đến hd)
hek2mgl

4
Bạn cần echo json_decode('"\u201B"');. Dấu ngoặc kép xung quanh biểu tượng unicode là bắt buộc.
Stefan Gehrig

162

PHP 7.0.0 đã giới thiệu cú pháp "Thoát mã codepoint" .

Bây giờ có thể dễ dàng viết các ký tự Unicode bằng cách sử dụng một chuỗi trích dẫn kép hoặc chuỗi heredoc , mà không cần gọi bất kỳ chức năng nào.

$unicodeChar = "\u{1000}";

Điều này có thể được sử dụng như vậy: wordwrap($longLongText, 20, "\u{200B}", true);( không gian có chiều rộng bằng không )
sanmai

5
Tôi tin rằng OP muốn câu trả lời này, không phải câu trả lời được chấp nhận. Ở bất cứ giá nào, khi tôi tìm kiếm "Unicode trong PHP", đó là vì tôi muốn câu trả lời này chứ không phải câu trả lời được chấp nhận. Có lẽ "\ u {abcd}" không tồn tại khi câu hỏi này được hỏi lần đầu tiên. Nếu vậy, câu trả lời được chấp nhận bây giờ sẽ được di chuyển.
Adam Chalcraft

23

Tôi tự hỏi tại sao chưa ai đề cập đến điều này, nhưng bạn có thể thực hiện một phiên bản gần như tương đương bằng cách sử dụng các chuỗi thoát trong chuỗi trích dẫn kép :

\x[0-9A-Fa-f]{1,2}

Chuỗi các ký tự khớp với biểu thức chính quy là một ký tự trong ký hiệu thập lục phân.

Ví dụ ASCII:

<?php
    echo("\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21");
?>

Chào thế giới!

Vì vậy, đối với trường hợp của bạn, tất cả những gì bạn cần làm là $str = "\x30\xA2";. Nhưng đây là byte , không phải ký tự. Biểu diễn byte của bảng mã Unicode trùng với endian lớn UTF-16, vì vậy chúng tôi có thể in trực tiếp ra như vậy:

<?php
    header('content-type:text/html;charset=utf-16be');
    echo("\x30\xA2");
?>

Nếu bạn đang sử dụng một mã hóa khác, bạn sẽ cần thay đổi các byte tương ứng (hầu hết được thực hiện với một thư viện, mặc dù cũng có thể bằng tay).

Ví dụ về endian UTF-16:

<?php
    header('content-type:text/html;charset=utf-16le');
    echo("\xA2\x30");
?>

Ví dụ UTF-8:

<?php
    header('content-type:text/html;charset=utf-8');
    echo("\xE3\x82\xA2");
?>

Ngoài ra còn có packchức năng, nhưng bạn có thể mong đợi nó sẽ chậm.


Hoàn hảo khi sao chép / dán ký tự dấu đầu dòng (\ xE2 \ x80 \ xA2) có thể dẫn đến lỗi mã hóa UTF-8 trong tài liệu nguồn. Cảm ơn bạn.
dong dỏng

21

PHP không biết các chuỗi thoát Unicode này. Nhưng vì các chuỗi thoát không xác định vẫn không bị ảnh hưởng, bạn có thể viết hàm riêng của mình để chuyển đổi các chuỗi thoát Unicode đó:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', create_function('$match', 'return mb_convert_encoding(pack("H*", $match[1]), '.var_export($encoding, true).', "UTF-16BE");'), $str);
}

Hoặc với biểu thức hàm ẩn danh thay vì create_function:

function unicodeString($str, $encoding=null) {
    if (is_null($encoding)) $encoding = ini_get('mbstring.internal_encoding');
    return preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/u', function($match) use ($encoding) {
        return mb_convert_encoding(pack('H*', $match[1]), $encoding, 'UTF-16BE');
    }, $str);
}

Cách sử dụng của nó:

$str = unicodeString("\u1000");

10
html_entity_decode('&#x30a8;', 0, 'UTF-8');

Điều này làm việc quá. Tuy nhiên, giải pháp json_decode () nhanh hơn rất nhiều (khoảng 50 lần).


Phương pháp đơn giản, thanh lịch, đơn giản và hoàn toàn an toàn. +10
andreszs


3

Như đã đề cập bởi những người khác, PHP 7 giới thiệu hỗ trợ \utrực tiếp cho cú pháp Unicode.

Như những người khác đã đề cập, cách duy nhất để có được giá trị chuỗi từ bất kỳ mô tả ký tự Unicode hợp lý nào trong PHP, là chuyển đổi nó từ một thứ khác (ví dụ: phân tích cú pháp JSON, phân tích cú pháp HTML hoặc một số dạng khác). Nhưng điều này đi kèm với một chi phí hiệu suất thời gian chạy.

Tuy nhiên, có một lựa chọn khác. Bạn có thể mã hóa ký tự trực tiếp trong PHP bằng cách \xthoát nhị phân. Các \xcú pháp thoát cũng được hỗ trợ trong PHP 5 .

Điều này đặc biệt hữu ích nếu bạn không muốn nhập ký tự trực tiếp vào một chuỗi thông qua hình thức tự nhiên của nó. Ví dụ: nếu đó là một ký tự điều khiển vô hình hoặc khó phát hiện khoảng trắng khác.

Đầu tiên, một ví dụ bằng chứng:

// Unicode Character 'HAIR SPACE' (U+200A)
$htmlEntityChar = "&#8202;";
$realChar = html_entity_decode($htmlEntityChar);
$phpChar = "\xE2\x80\x8A";
echo 'Proof: ';
var_dump($realChar === $phpChar); // bool(true)

Lưu ý rằng, như Pacerier đã đề cập trong một câu trả lời khác, mã nhị phân này là duy nhất cho một mã hóa ký tự cụ thể. Trong ví dụ trên, \xE2\x80\x8Alà mã hóa nhị phân cho U + 200A trong UTF-8.

Câu hỏi tiếp theo là, làm thế nào để bạn nhận được từ U+200Ađể \xE2\x80\x8A?

Dưới đây là tập lệnh PHP để tạo chuỗi thoát cho bất kỳ ký tự nào, dựa trên chuỗi JSON, thực thể HTML hoặc bất kỳ phương thức nào khác khi bạn có chuỗi đó dưới dạng chuỗi gốc.

function str_encode_utf8binary($str) {
    /** @author Krinkle 2018 */
    $output = '';
    foreach (str_split($str) as $octet) {
        $ordInt = ord($octet);
        // Convert from int (base 10) to hex (base 16), for PHP \x syntax
        $ordHex = base_convert($ordInt, 10, 16);
        $output .= '\x' . $ordHex;
    }
    return $output;
}

function str_convert_html_to_utf8binary($str) {
    return str_encode_utf8binary(html_entity_decode($str));
}
function str_convert_json_to_utf8binary($str) {
    return str_encode_utf8binary(json_decode($str));
}

// Example for raw string: Unicode Character 'INFINITY' (U+221E)
echo str_encode_utf8binary('∞') . "\n";
// \xe2\x88\x9e

// Example for HTML: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_html_to_utf8binary('&#8202;') . "\n";
// \xe2\x80\x8a

// Example for JSON: Unicode Character 'HAIR SPACE' (U+200A)
echo str_convert_json_to_utf8binary('"\u200a"') . "\n";
// \xe2\x80\x8a

0
function unicode_to_textstring($str){

    $rawstr = pack('H*', $str);

    $newstr =  iconv('UTF-16BE', 'UTF-8', $rawstr);
    return $newstr;
}

$ dir = '67714eac99c500200054006f006b0079006f002000530074006100740069006f006e003a0020';

echo unicode_to lòng chuỗi ($ str);

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.