PHP: ayrı karakter böler Çokbaytlı string (kelime)

4 Cevap php

Hiç şans ile mb_split kullanarak (ben bir dizi gerekir) ayrı karakter içine bu dize "主楼 怎么 走" bölmek için çalışıyor ... Herhangi bir öneriniz?

Teşekkür ederiz!

4 Cevap

Örneğin, 'u' seçeneği ile bir düzenli ifade deneyin

  $chars = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);

Bunu yapmak için çirkin bir yoldur:

mb_internal_encoding("UTF-8"); // this IS A MUST!! PHP has trouble with multibyte
                               // when no internal encoding is set!
$string = ".....";
$chars = array();
for ($i = 0; $i < mb_strlen($string); $i++ ) {
    $chars[] = mb_substr($string, $i, 1); // only one char to go to the array
}

Ayrıca daha önce internal_encoding ayarı ile mb_split ile yol denemelisiniz.

Sen grapheme fonksiyonları (PHP 5.3 veya intl 1.0) ve IntlBreakIterator (PHP 5.5 veya intl 3.0) kullanabilirsiniz. Aşağıdaki kod intl ve mbstring ve PCRE'nin işlevleri arasında diffrence gösterir.

// http://www.php.net/manual/function.grapheme-strlen.php
$string = "a\xCC\x8A"  // 'LATIN SMALL LETTER A WITH RING ABOVE' (U+00E5)
         ."o\xCC\x88"; // 'LATIN SMALL LETTER O WITH DIAERESIS'  (U+00F6)

$expected = ["a\xCC\x8A", "o\xCC\x88"];
$expected2 = ["a", "\xCC\x8A", "o", "\xCC\x88"];

var_dump(
    $expected === str_to_array($string),
    $expected === str_to_array2($string),
    $expected2 === str_to_array3($string),
    $expected2 === str_to_array4($string),
    $expected2 ===  str_to_array5($string)
);

function str_to_array($string)
{
    $length = grapheme_strlen($string);
    $ret = [];

    for ($i = 0; $i < $length; $i += 1) {
        $ret[] = grapheme_substr($string, $i, 1);
    }

    return $ret;
}

function str_to_array2($string)
{
    $it = IntlBreakIterator::createCharacterInstance('en_US');
    $it->setText($string);

    $ret = [];
    $prev = 0;

    foreach ($it as $pos) {

        $char = substr($string, $prev, $pos - $prev);

        if ('' !== $char) {
           $ret[] = $char;
        }

        $prev = $pos;
    }

    return $ret;
}

function str_to_array3($string)
{
    $it = IntlBreakIterator::createCodePointInstance();
    $it->setText($string);

    $ret = [];
    $prev = 0;

    foreach ($it as $pos) {

        $char = substr($string, $prev, $pos - $prev);

        if ('' !== $char) {
           $ret[] = $char;
        }

        $prev = $pos;
    }

    return $ret;
}

function str_to_array4($string)
{
    $length = mb_strlen($string, "UTF-8");
    $ret = [];

    for ($i = 0; $i < $length; $i += 1) {
        $ret[] = mb_substr($string, $i, 1, "UTF-8");
    }

    return $ret;
}

function str_to_array5($string) {
    return preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
}

Üretim ortamında çalışırken, neredeyse tüm sesletim ve Mbstring işlevler geçersiz bayt dizisi işleyemez beri yedek karakteri ile geçersiz bayt dizisi değiştirmeniz gerekir. http://stackoverflow.com/a/13695364/531320: Eğer bir ilgi varsa, benim geçmiş cevap görmek

Eğer perfomance almak istemiyorsanız, htmlspecialchars'ın ve htmlspecialchars_decode kullanılabilir. Bu şekilde hak UTF-8 dışında çeşitli kodlama desteklemektedir.

function str_to_array6($string, $encoding = 'UTF-8')
{
    $ret = [];
    str_replace_callback($string, function($char, $index) use (&$ret) { $ret[] = $char; return ''; }, $encoding);
    return $ret;
}

function str_replace_callback($string, $callable, $encoding = 'UTF-8')
{
    $str_size = strlen($string);
    $string = str_scrub($string, $encoding);

    $ret = '';
    $char = '';
    $index = 0;

    for ($pos = 0; $pos < $str_size; ++$pos) {

        $char .= $string[$pos];

        if (str_check_encoding($char, $encoding)) {

            $ret .= $callable($char, $index);
            $char = '';
            ++$index;
        }

    }

    return $ret;
}

function str_check_encoding($string, $encoding = 'UTF-8')
{
    $string = (string) $string;
    return $string === htmlspecialchars_decode(htmlspecialchars($string, ENT_QUOTES, $encoding));
}

function str_scrub($string, $encoding = 'UTF-8')
{
    return htmlspecialchars_decode(htmlspecialchars($string, ENT_SUBSTITUTE, $encoding));
}

UTF-8'in özelliklerini öğrenmek istiyorsanız, bayt manipülasyon uygulama için iyi bir yoldur.

function str_to_array6($string)
{
    // REPLACEMENT CHARACTER (U+FFFD)
    $substitute = "\xEF\xBF\xBD";
    $size = strlen($string);
    $ret = [];

    for ($i = 0; $i < $size; $i += 1) {

        if ($string[$i] <= "\x7F") {

            $ret[] = $string[$i];

        } elseif ("\xC2" <= $string[$i] && $string[$i] <= "\xDF")  {

            if (!isset($string[$i+1])) {

                $ret[] = $substitute;
                return $ret;

            } elseif ($string[$i+1] < "\x80" || "\xBF" < $string[$i+1]) {

                $ret[] = $substitute;

            } else {

                $ret[] = substr($string, $i, 2);
                $i += 1;

            }

        } elseif ("\xE0" <= $string[$i] && $string[$i] <= "\xEF") {

            $left = "\xE0" === $string[$i] ? "\xA0" : "\x80";
            $right = "\xED" === $string[$i] ? "\x9F" : "\xBF";

            if (!isset($string[$i+1])) {

                $ret[] = $substitute;
                return $ret;

            } elseif ($string[$i+1] < $left || $right < $string[$i+1]) {

                $ret[] = $substitute;

            } else {

                if (!isset($string[$i+2])) {

                    $ret[] = $substitute;
                    return $ret;

                } elseif ($string[$i+2] < "\x80" || "\xBF" < $string[$i+2]) {

                    $ret[] = $substitute;
                    $i += 1;

                } else {

                    $ret[] = substr($string, $i, 3);
                    $i += 2;

                }

            }

        } elseif ("\xF0" <= $string[$i] && $string[$i] <= "\xF4") {

            $left = "\xF0" === $string[$i] ? "\x90" : "\x80";
            $right = "\xF4" === $string[$i] ? "\x8F" : "\xBF";

            if (!isset($string[$i+1])) {

                $ret[] = $substitute;
                return $ret;

            } elseif ($string[$i+1] < $left || $right < $string[$i+1]) {

                $ret[] = $substitute;

            } else {

                if (!isset($string[$i+2])) {

                    $ret[] = $substitute;
                    return $ret;

                } elseif ($string[$i+2] < "\x80" || "\xBF" < $string[$i+2]) {

                    $ret[] = $substitute;
                    $i += 1;

                } else {

                    if (!isset($string[$i+3])) {

                        $ret[] = $substitute;
                        return $ret;

                    } elseif ($string[$i+3] < "\x80" || "\xBF" < $string[$i+3]) {

                        $ret[] = $substitute;
                        $i += 2;

                    } else {

                        $ret[] = substr($string, $i, 4);
                        $i += 3;

                    }

                }

            }

        } else {

            $ret[] = $substitute;

        }

    }

    return $ret;

}

Bu işlevler arasında kıyaslama sonucu burada.

grapheme
0.12967610359192
IntlBreakIterator::createCharacterInstance
0.17032408714294
IntlBreakIterator::createCodePointInstance
0.079245090484619
mbstring
0.081080913543701
preg_split
0.043133974075317
htmlspecialchars
0.25599694252014
byte maniplulation
0.13132810592651

Kriter kodu burada.

$string = '主楼怎么走';

foreach (timer([
    'grapheme' => 'str_to_array',
    'IntlBreakIterator::createCharacterInstance' => 'str_to_array2',
    'IntlBreakIterator::createCodePointInstance' => 'str_to_array3',
    'mbstring' => 'str_to_array4',
    'preg_split' => 'str_to_array5',
    'htmlspecialchars' => 'str_to_array6',
    'byte maniplulation' => 'str_to_array7'
],
[$string]) as $desc => $time) {

  echo $desc, PHP_EOL,
       $time, PHP_EOL; 
}

function timer(array $callables, array $arguments, $repeat = 10000) {

    $ret = [];
    $save = $repeat;

    foreach ($callables as $key => $callable) {

        $start = microtime(true);

        do {

            array_map($callable, $arguments);

        } while($repeat -= 1);

        $stop = microtime(true);
        $ret[$key] = $stop - $start;
        $repeat = $save;

    }

    return $ret;
}

Bunun için () str_split kullanmak istiyorsunuz.

$string = "主楼怎么走";
$array = str_split($string);
echo $array[0]; // would output 主