PHP verilen bayt sayısını uygun bir UTF-8 dizesi kesecek

6 Cevap php

Bir UTF-8 dizesi $s var ve N bayt saklanabilir böylece biz onu kısaltmak gerektiğini söylüyorlar. Körü körüne o kadar N bayt olabilir karışıklık için kesiliyor. Ama karakter sınırlarını bulmak için Çözümün bir drag. Derli toplu bir yolu var mı?

[Düzenle 20100414] S.Mark 's cevap ek olarak: mb_strcut(), geçenlerde işi yapmak için başka bir işlevi bulundu: grapheme_extract($s, $n, GRAPHEME_EXTR_MAXBYTES); {[(3) den }] uzantısı. Intl bir YBÜ sarıcı olduğundan, bunu güven çok şey var.

6 Cevap

Ben size sadece mb_strcut kullanmak ve UTF-8 İlk kodlaması ayarlamak emin olun ki, tekerleği yeniden icat etmeye gerek yok sanırım.

mb_internal_encoding('UTF-8');
echo mb_strcut("\xc2\x80\xc2\x80", 0, 3); //from index 0, cut 3 characters.

dönüş

\xc2\x80

in \ xc2 \ x80 \ xc2 çünkü, sonuncusu geçersiz

Edit: S.Mark 'un cevabı aslında benimkinden daha iyidir - PHP tam olarak bu sorunu çözen bir (kötü belgelenmiş) yerleşik işlevi vardır.

Orijinal "geri bite" cevabı şöyle:

  • Istenilen byte saymak kesecek
  • Son byte 110 (ikili) ile başlar, aynı zamanda onu bırakın
  • Ikinci-to-son byte 1110 (ikili) ile başlar, son 2 byte bırakın
  • Üçüncü ve son byte 11110 (ikili) ile başlar, son 3 byte bırakın

Bu, UTF-8 kesiliyor yanlış gidebilir ana şey sonunda bir incomplete character sarkan, yok olmasını sağlar.

Ne yazık ki (Andrew açıklamalarda hatırlatıyor) gibi iki ayrı kodlanmış Unicode kod noktaları tek bir karakter (temelde, örneğin aksan gibi Aksanları önceki harfi değiştirerek ayrı bir kod noktası olarak temsil edilebilir) oluşturmak durumlar da vardır.

Bu tür bir şey Taşıma PHP mevcut değildir ve hatta tüm durumlar için (orada! Somne weird komut vardır) mümkün olmayabilir hangi gelişmiş Unicode-Fu gerektirir, ama neyse ki en azından nispeten nadir Latince tabanlı diller için.

I coded up this simple function for this purpose, you need mb_string olsa.

function str_truncate($string, $bytes = null)
{
    if (isset($bytes) === true)
    {
    	// to speed things up
    	$string = mb_substr($string, 0, $bytes, 'UTF-8');

    	while (strlen($string) > $bytes)
    	{
    		$string = mb_substr($string, 0, -1, 'UTF-8');
    	}
    }

    return $string;
}

While this code also works, S.Mark answer gitmek için yol besbelli.

İşte mb_strcut() için bir test. Bu bizim aradığımız sadece ne yapar ama oldukça inandırıcı bulmak olduğunu ispat etmez.

<?php
ini_set('default_charset', 'UTF-8' );
$strs = array(
    'Iñtërnâtiônàlizætiøn',
    'החמאס: רוצים להשלים את עסקת שליט במהירות האפשרית',
    'ايران لا ترى تغييرا في الموقف الأمريكي',
    '独・米で死傷者を出した銃の乱射事件',
    '國會預算處公布驚人的赤字數據後',
    '이며 세계 경제 회복에 걸림돌이 되고 있다',
    'В дагестанском лесном массиве южнее села Какашура',
    'นายประสิทธิ์ รุ่งสะอาด ปลัดเทศบาล รักษาการแทนนายกเทศมนตรี ต.ท่าทองใหม่',
    'ભારતીય ટીમનો સુવર્ણ યુગ : કિવીઝમાં પણ કમાલ',
    'ཁམས་དཀར་མཛེས་ས་ཁུལ་དུ་རྒྱ་གཞུང་ལ་ཞི་བའི་ངོ་རྒོལ་',
    'Χιόνια, βροχές και θυελλώδεις άνεμοι συνθέτουν το',
    'Հայաստանում սկսվել է դատական համակարգի ձեւավորումը',
    'რუსეთი ასევე გეგმავს სამხედრო');
for ( $i = 10; $i <= 30; $i += 5 ) {
    foreach ($strs as $s) {
        $t = mb_strcut($s, 0, $i, 'UTF-8');
        print(
            sprintf('%3s%3s ', mb_strlen($t, 'UTF-8'), mb_strlen($t, 'latin1'))
            . ( mb_check_encoding($t, 'UTF-8') ? ' OK  ' : ' Bad ' )
            . $t . "\n");
    }
}
?>

mb_strcut(), Geçenlerde benzer bir işi yapmak için başka bir işlevi bulunan S.Mark 's cevap ek olarak: grapheme_extract($s, $n, GRAPHEME_EXTR_MAXBYTES); intl den uzantısı.

Işlevselliği biraz farklı: mb_strcut() belgelerine yakın UTF-8 karakter sınırında keser iddia, yani grapheme_extract(), OTOH, yok iken çoklu karakter graphemes saygı duymuyor. Peki neye ihtiyacınız bağlı olarak, grapheme_extract() daha iyi olabilir (örneğin, bir dizesini görüntülemek için) veya mb_strcut() (indeksleme örneğin) daha iyi olabilir. Neyse, ben o söz ediyorum sadece olsa.

(Intl bir YBÜ sarıcı beri, ben bunu güven çok şey var.)

No. There is no way to do this other than decoding. kodlama ancak oldukça mekaniktir. wikipedia article olarak güzel tabloya bakın

Edit: Michael Borgwardt bütün dize çözme olmadan bunu nasıl bize gösteriyor. Clever.