PHP Unicode karakter bir diziye bir dize bölmek için en iyi yolu nedir?

4 Cevap php

PHP < 6, Unicode karakter bir diziye bir dize bölmek için en iyi yolu nedir? Giriş zorunlu UTF-8 değilse?

Ben bir giriş dizesi Unicode karakter kümesi Unicode karakter başka kümesinin bir alt kümesidir olup olmadığını bilmek istiyorum.

Cevapların ilk çift vermedi Neden olarak, fonksiyonların mb_ ailesi için düz koşmak değil?

4 Cevap

Sen PCRE regex 'u' değiştirici kullanabilirsiniz; Pattern Modifiers (alıntı) bakın:

u (PCRE8)

This modifier turns on additional functionality of PCRE that is incompatible with Perl. Pattern strings are treated as UTF-8. This modifier is available from PHP 4.1.0 or greater on Unix and from PHP 4.2.3 on win32. UTF-8 validity of the pattern is checked since PHP 4.3.5.

Örneğin, bu kodu düşünüyor:

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

Sen kullanılamaz bir sonuç alırsınız:

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)

Ancak, bu kod ile:

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

(Notice the 'u' at the end of the regex)

Siz ne istediğinizi alabilirsiniz:

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)

Bu :-) yardımcı olur umarım

Bu deneyin:

preg_match_all('/./u', $text, $array);

Regex yolu sizin için yeterli değil nedense eğer. Ben bir kez terk edilir ama sen kendi üzerinde bunu yapmak için karar verirseniz size yardımcı olabilir Zend_Locale_UTF8 hangi yazdı.

Özellikle Unicode dizeleri okur ve onlarla çalışmak için (tabii ki birden fazla bayt dışında oluşabilir) tek karakter bunları böler Zend_Locale_UTF8_PHP5_String sınıfında bakabilirsiniz.

EDIT: I just relaized that ZF's svn-browser is down so I copied the important methods for convenience:

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

Ben dize indeksleme hızlandırmak için muhtemelen aptalca bir girişimi UTF-16 ve geri gezisi dahil, mb_* kullanarak bir çözüm yazabildi:

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

I mb_internal_encoding ve sadece her mb_* çağrısı şeyi belirterek kaçınarak iyi bir şans oldu. Ben preg çözümü kullanarak rüzgar eminim.