อักขระ Unicode ในสตริง PHP


164

คำถามนี้ดูเรียบง่าย แต่ไม่สามารถหาคำตอบได้

PHP เทียบเท่ากับโค้ด C # ต่อไปนี้คืออะไร?

string str = "\u1000";

ตัวอย่างนี้สร้างสตริงที่มีอักขระ Unicode เดียวซึ่งมี "ค่าตัวเลข Unicode" คือ 1000 ในเลขฐานสิบหก (4096 เป็นทศนิยม)

นั่นคือใน PHP ฉันจะสร้างสตริงที่มีอักขระ Unicode ตัวเดียวที่รู้จักกันในชื่อ "ค่าตัวเลข Unicode" ได้อย่างไร



4
@diEcho: สำหรับการจับคู่อักขระ Unicode เท่านั้น แต่ OP ต้องการสร้างให้กับอักขระเหล่านั้น
Stefan Gehrig

สิ่งนี้อาจช่วยได้: randomchaos.com/documents/?source=php_and_unicode
diEcho

คำตอบ:


178

เนื่องจาก JSON สนับสนุน\uxxxxไวยากรณ์โดยตรงสิ่งแรกที่อยู่ในใจของฉันคือ:

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

ตัวเลือกอื่นจะใช้ mb_convert_encoding()

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

หรือใช้ประโยชน์จากการทำแผนที่โดยตรงระหว่าง UTF-16BE (big endian) และ Unicode codepoint:

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

9
JSON ไม่ใช่ JavaScript
Gumbo

4
@Gumbo: ฉันรู้ แต่ก็ไม่ได้สร้างความแตกต่างในที่นี่ จาวาสคริปต์รวมถึง JSON รองรับ\uxxxxไวยากรณ์ Unicode เพื่อให้คุณสามารถใช้json_decodeในการทำงานกับการแสดงสตริง JSON ที่สร้างขึ้นเอง ฉันเปลี่ยนถ้อยคำแม้ว่าจะมีคำอธิบายที่ชัดเจน
Stefan Gehrig

3
ตกลงดังนั้นสูตรที่เข้มงวดของหนึ่งคำตอบสำหรับคำถามของฉันคือ: $ str = json_decode ('"\ u1000"'); ขอบคุณ.
Telaclavo

ฉันพยายามecho json_decode('\u201B');ซึ่ง referes ไปอ้างหวนกลับเดียวแต่จะไม่ทำงานหมายถึงการส่งออกไม่มี (แม้ว่าจะประปาhd)
hek2mgl

4
echo json_decode('"\u201B"');คุณจำเป็นต้อง เครื่องหมายอัญประกาศคู่ล้อมรอบสัญลักษณ์ยูนิโค้ดเป็นสิ่งจำเป็น
Stefan Gehrig

162

PHP 7.0.0 ได้แนะนำ"Unicode codepoint หลบหนี" ไวยากรณ์

ตอนนี้คุณสามารถเขียนอักขระ Unicode ได้อย่างง่ายดายโดยใช้double- quoteหรือสตริงheredocโดยไม่ต้องเรียกใช้ฟังก์ชันใด ๆ

$unicodeChar = "\u{1000}";

สิ่งนี้สามารถใช้งานได้เช่น: wordwrap($longLongText, 20, "\u{200B}", true);( พื้นที่กว้างเป็นศูนย์ )
sanmai

5
ฉันเชื่อว่า OP ต้องการคำตอบนี้ไม่ใช่คำตอบที่ยอมรับ เมื่อฉันค้นหา "Unicode ใน PHP" มันเป็นเพราะฉันต้องการคำตอบนี้ไม่ใช่คำตอบที่ยอมรับ อาจเป็น "\ u {abcd}" ไม่ได้เมื่อถามคำถามนี้เป็นครั้งแรก ถ้าเป็นเช่นนั้นคำตอบที่ได้รับการยอมรับควรจะย้ายตอนนี้
Adam Chalcraft

23

ฉันสงสัยว่าทำไมยังไม่มีใครพูดถึงเรื่องนี้ แต่คุณสามารถทำเวอร์ชั่นที่เทียบเท่ากันได้โดยใช้ escape sequences ในสตริงที่ยกมาสองชั้น :

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

ลำดับของอักขระที่ตรงกับนิพจน์ทั่วไปคืออักขระในรูปแบบเลขฐานสิบหก

ตัวอย่าง ASCII:

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

สวัสดีชาวโลก!

$str = "\x30\xA2";ดังนั้นสำหรับกรณีของคุณทั้งหมดที่คุณต้องทำคือ แต่นี่เป็นไบต์ไม่ใช่ตัวอักษร การแทนค่าไบต์ของ Unicode codepoint เกิดขึ้นพร้อมกับ UTF-16 big endian ดังนั้นเราจึงสามารถพิมพ์ออกมาได้โดยตรงเช่น:

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

หากคุณกำลังใช้การเข้ารหัสที่แตกต่างกันคุณจะต้องแก้ไขไบต์ตามลำดับ (ส่วนใหญ่ทำด้วยห้องสมุด แต่เป็นไปได้ด้วยมือ)

ตัวอย่าง endian เล็ก ๆ ของ UTF-16:

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

ตัวอย่าง UTF-8:

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

นอกจากนี้ยังมีpackฟังก์ชั่น แต่คุณสามารถคาดหวังว่ามันจะช้า


สมบูรณ์แบบสำหรับเมื่อคัดลอก / วางอักขระหัวข้อย่อย (\ xE2 \ x80 \ xA2) อาจทำให้เกิดข้อผิดพลาดในการเข้ารหัส UTF-8 ในเอกสารต้นฉบับ ขอบคุณ.
jimp

21

PHP ไม่ทราบลำดับการหลบหนีของ Unicode แต่เนื่องจาก escape sequences ที่ไม่รู้จักยังคงไม่ได้รับผลกระทบคุณสามารถเขียนฟังก์ชันของคุณเองที่แปลง Unicode escape ดังนี้:

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);
}

หรือด้วยนิพจน์ฟังก์ชันนิรนามแทน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);
}

การใช้งาน:

$str = unicodeString("\u1000");

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

มันก็ใช้ได้เช่นกัน อย่างไรก็ตามโซลูชัน json_decode () นั้นเร็วกว่ามาก (ประมาณ 50 เท่า)


วิธีการที่เรียบง่ายสง่างามตรงไปตรงมาและปลอดภัยโดยสิ้นเชิง +10
andreszs


3

PHP 7 แนะนำการรองรับ\uไวยากรณ์ Unicode โดยตรง

ตามที่ผู้อื่นกล่าวถึงวิธีเดียวที่จะได้รับค่าสตริงจากคำอธิบายอักขระ Unicode ที่เหมาะสมใน PHP คือการแปลงจากสิ่งอื่น (เช่นการแยก JSON, การแยกวิเคราะห์ JSON, HTML การแยกหรือรูปแบบอื่น ๆ ) แต่สิ่งนี้มาพร้อมกับประสิทธิภาพค่าใช้จ่ายในการทำงาน

อย่างไรก็ตามมีอีกหนึ่งตัวเลือก คุณสามารถเข้ารหัสอักขระโดยตรงใน PHP ด้วยการ\xหลบหนีแบบไบนารี \xไวยากรณ์หลบหนีนอกจากนี้ยังได้รับการสนับสนุนใน PHP 5

สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณไม่ต้องการใส่อักขระโดยตรงในสตริงผ่านรูปแบบธรรมชาติ ตัวอย่างเช่นถ้ามันเป็นตัวควบคุมที่มองไม่เห็นหรืออื่น ๆ ที่ยากที่จะตรวจสอบช่องว่าง

ครั้งแรกตัวอย่างหลักฐาน:

// 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)

โปรดทราบว่าตามที่ Pacerier พูดถึงในคำตอบอื่นรหัสเลขฐานสองนี้เป็นรหัสเฉพาะสำหรับการเข้ารหัสอักขระเฉพาะ ในตัวอย่างข้างต้น\xE2\x80\x8Aเป็นการเข้ารหัสแบบไบนารีสำหรับ U + 200A ใน UTF-8

คำถามต่อไปคือคุณจะU+200Aไปจากได้\xE2\x80\x8Aอย่างไร

ด้านล่างนี้เป็นสคริปต์ PHP เพื่อสร้างลำดับการยกเว้นสำหรับตัวละครใด ๆ โดยอิงจากสตริง JSON, เอนทิตี HTML หรือวิธีอื่นใด ๆ เมื่อคุณมีมันเป็นสตริงดั้งเดิม

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;
}

$ msg = '67714eac99c500200054006f006b0079006f002000530074006100740069006f006e003a0020';

echo unicode_to_textstring ($ str);

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.