Каков наилучший способ разбить строку на массив символов Unicode в PHP?

Я использую этот объект. Значения кодируются, поэтому их необходимо учитывать при чтении или записи со стороны сервера.

cookie = (function() {

/**
 * Sets a cookie value. seconds parameter is optional
 */
var set = function(name, value, seconds) {
    var expires = seconds ? '; expires=' + new Date(new Date().getTime() + seconds * 1000).toGMTString() : '';
    document.cookie = name + '=' + encodeURIComponent(value) + expires + '; path=/';
};

var map = function() {
    var map = {};
    var kvs = document.cookie.split('; ');
    for (var i = 0; i < kvs.length; i++) {
        var kv = kvs[i].split('=');
        map[kv[0]] = decodeURIComponent(kv[1]);
    }
    return map;
};

var get = function(name) {
    return map()[name];
};

var remove = function(name) {
    set(name, '', -1);
};

return {
    set: set,
    get: get,
    remove: remove,
    map: map
};

})();
13
задан IMSoP 19 December 2018 в 09:55
поделиться

4 ответа

Вы можете использовать модификатор u с регулярным выражением PCRE; см. Модификаторы шаблонов (цитата): функциональность PCRE, то есть несовместим с Perl. Шаблон строки обрабатываются как UTF-8. Эта модификатор доступен с PHP 4.1.0 или выше в Unix и с PHP 4.2.3 на win32. UTF-8 действительность шаблон проверяется начиная с PHP 4.3.5.

Например, учитывая этот код:

header('Content-type: text/html; charset=UTF-8');  // So the browser doesn't make our lives harder
$str = "abc 文字化け, efg";

$results = array();
preg_match_all('/./', $str, $results);
var_dump($results[0]);

Вы получите непригодный для использования результат:

array
  0 => string 'a' (length=1)
  1 => string 'b' (length=1)
  2 => string 'c' (length=1)
  3 => string ' ' (length=1)
  4 => string '�' (length=1)
  5 => string '�' (length=1)
  6 => string '�' (length=1)
  7 => string '�' (length=1)
  8 => string '�' (length=1)
  9 => string '�' (length=1)
  10 => string '�' (length=1)
  11 => string '�' (length=1)
  12 => string '�' (length=1)
  13 => string '�' (length=1)
  14 => string '�' (length=1)
  15 => string '�' (length=1)
  16 => string ',' (length=1)
  17 => string ' ' (length=1)
  18 => string 'e' (length=1)
  19 => string 'f' (length=1)
  20 => string 'g' (length=1)

Но с этим кодом:

header('Content-type: text/html; charset=UTF-8');  // So the browser doesn't make our lives harder
$str = "abc 文字化け, efg";

$results = array();
preg_match_all('/./u', $str, $results);
var_dump($results[0]);

(Обратите внимание на 'u' в конец регулярного выражения)

Вы получаете то, что хотите:

array
  0 => string 'a' (length=1)
  1 => string 'b' (length=1)
  2 => string 'c' (length=1)
  3 => string ' ' (length=1)
  4 => string '文' (length=3)
  5 => string '字' (length=3)
  6 => string '化' (length=3)
  7 => string 'け' (length=3)
  8 => string ',' (length=1)
  9 => string ' ' (length=1)
  10 => string 'e' (length=1)
  11 => string 'f' (length=1)
  12 => string 'g' (length=1)

Надеюсь, это поможет: -)

17
ответ дан 1 December 2019 в 07:52
поделиться

Попробуйте следующее:

preg_match_all('/./u', $text, $array);
6
ответ дан 1 December 2019 в 07:52
поделиться

Мне удалось написать решение, используя mb _ * , включая переход на UTF-16 и обратно в, вероятно, глупой попытке ускорить индексацию строк:

$japanese2 = mb_convert_encoding($japanese, "UTF-16", "UTF-8");
$length = mb_strlen($japanese2, "UTF-16");
for($i=0; $i<$length; $i++) {
    $char = mb_substr($japanese2, $i, 1, "UTF-16");
    $utf8 = mb_convert_encoding($char, "UTF-8", "UTF-16");
    print $utf8 . "\n";
}

Мне больше повезло избежать mb_internal_encoding и просто указывать все при каждом вызове mb _ * . Я уверен, что остановлюсь на решении preg .

0
ответ дан 1 December 2019 в 07:52
поделиться

Если по какой-то причине вам недостаточно регулярного выражения. Однажды я написал Zend_Locale_UTF8 , который заброшен, но может помочь вам, если вы решите сделать это самостоятельно.

В частности, обратите внимание на класс Zend_Locale_UTF8_PHP5_String , который читается в Строки Unicode и для работы с ними разбивают их на отдельные символы (которые, очевидно, могут состоять из нескольких байтов).

EDIT : Я только что сообщил, что svn-браузер ZF не работает, поэтому для удобства я скопировал важные методы:

/**
 * Returns the UTF-8 code sequence as an array for any given $string.
 *
 * @access protected
 * @param string|integer $string
 * @return array
 */
protected function _decode( $string ) {

    $string     = (string) $string;
    $length     = strlen($string);
    $sequence   = array();

    for ( $i=0; $i<$length; ) {
        $bytes      = $this->_characterBytes($string, $i);
        $ord        = $this->_ord($string, $bytes, $i);

        if ( $ord !== false )
            $sequence[] = $ord;

        if ( $bytes === false )
            $i++;
        else
            $i  += $bytes;
    }

    return $sequence;

}

/**
 * Returns the UTF-8 code of a character.
 *
 * @see http://en.wikipedia.org/wiki/UTF-8#Description
 * @access protected
 * @param string $string
 * @param integer $bytes
 * @param integer $position
 * @return integer
 */
protected function _ord( &$string, $bytes = null, $pos=0 )
{
    if ( is_null($bytes) )
        $bytes = $this->_characterBytes($string);

    if ( strlen($string) >= $bytes ) {

        switch ( $bytes ) {
            case 1:
                return ord($string[$pos]);
                break;

            case 2:
                return  ( (ord($string[$pos])   & 0x1f) << 6 ) +
                        ( (ord($string[$pos+1]) & 0x3f) );
                break;

            case 3:
                return  ( (ord($string[$pos])   & 0xf)  << 12 ) + 
                        ( (ord($string[$pos+1]) & 0x3f) << 6 ) +
                        ( (ord($string[$pos+2]) & 0x3f) );
                break;

            case 4:
                return  ( (ord($string[$pos])   & 0x7)  << 18 ) + 
                        ( (ord($string[$pos+1]) & 0x3f) << 12 ) + 
                        ( (ord($string[$pos+1]) & 0x3f) << 6 ) +
                        ( (ord($string[$pos+2]) & 0x3f) );
                break;

            case 0:
            default:
                return false;
        }
    }

    return false;
}
/**
 * Returns the number of bytes of the $position-th character.
 *
 * @see http://en.wikipedia.org/wiki/UTF-8#Description
 * @access protected
 * @param string $string
 * @param integer $position
 */
protected function _characterBytes( &$string, $position = 0 ) {
    $char       = $string[$position];
    $charVal    = ord($char);

    if ( ($charVal & 0x80) === 0 )
        return 1;

    elseif ( ($charVal & 0xe0) === 0xc0 )
        return 2;

    elseif ( ($charVal & 0xf0) === 0xe0 )
        return 3;

    elseif ( ($charVal & 0xf8) === 0xf0)
        return 4;
    /*
    elseif ( ($charVal & 0xfe) === 0xf8 )
        return 5;
    */

    return false;
}
1
ответ дан 1 December 2019 в 07:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: