Frage

Es wurde in einem angedeutet Kommentieren Sie eine Antwort auf diese Frage Dieser PHP kann Unicode -Zeichenfolgen nicht umkehren.

Unicode funktioniert in PHP, da die meisten Apps es als binär verarbeiten. Ja, PHP ist 8-Bit sauber. Versuchen Sie das Äquivalent davon in PHP: Perl -Mutf8 -e 'Print Scalar Reverse ("ほげほげ"). Sie erhalten Müll, nicht "げほげ ほ". - Jrockway

Und leider ist es richtig, dass PHPS Unicode Support ATM am besten "fehlt". Dieser Wille hoffentlich drastisch mit PHP6 verändern.

PHPS Multibyte -Funktionen Bietet die grundlegende Funktionalität, die Sie benötigen, um mit Unicode umzugehen, aber es ist inkonsistent und es fehlt viele Funktionen. Eine davon ist eine Funktion, um eine Zeichenfolge umzukehren.

Ich wollte diesen Text natürlich aus keinem anderen Grund umkehren, um herauszufinden, ob er möglich war. Und ich habe eine Funktion gemacht, um diese enorme komplexe Aufgabe zu erfüllen, diesen Unicode -Text umzukehren, damit Sie sich etwas länger entspannen können, bis er Php6 ist.

Testcode:

$enc = 'UTF-8';
$text = "ほげほげ";
$defaultEnc = mb_internal_encoding();

echo "Showing results with encoding $defaultEnc.\n\n";

$revNormal = strrev($text);
$revInt = mb_strrev($text);
$revEnc = mb_strrev($text, $enc);

echo "Original text is: $text .\n";
echo "Normal strrev output: " . $revNormal . ".\n";
echo "mb_strrev without encoding output: $revInt.\n";
echo "mb_strrev with encoding $enc output: $revEnc.\n";

if (mb_internal_encoding($enc)) {
    echo "\nSetting internal encoding to $enc from $defaultEnc.\n\n";

    $revNormal = strrev($text);
    $revInt = mb_strrev($text);
    $revEnc = mb_strrev($text, $enc);

    echo "Original text is: $text .\n";
    echo "Normal strrev output: " . $revNormal . ".\n";
    echo "mb_strrev without encoding output: $revInt.\n";
    echo "mb_strrev with encoding $enc output: $revEnc.\n";

} else {
    echo "\nCould not set internal encoding to $enc!\n";
}
War es hilfreich?

Lösung

GraphEm-Funktionen verarbeiten die UTF-8-Zeichenfolge korrekter als Mbstring und PCRE-Funktionen/ Mbstring und PCRE können Zeichen brechen. Sie können die Defferce zwischen ihnen sehen, indem Sie den folgenden Code ausführen.

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)
{
    $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_array3($string)
{
    return preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
}

function utf8_strrev($string)
{
    return implode(array_reverse(str_to_array($string)));
}

function utf8_strrev2($string)
{
    return implode(array_reverse(str_to_array2($string)));
}

function utf8_strrev3($string)
{
    return implode(array_reverse(str_to_array3($string)));
}

// http://www.php.net/manual/en/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)

var_dump(array_map(function($elem) { return strtoupper(bin2hex($elem)); },
[
  'should be' => "o\xCC\x88"."a\xCC\x8A",
  'grapheme' => utf8_strrev($string),
  'mbstring' => utf8_strrev2($string),
  'pcre' => utf8_strrev3($string)
]));

Das Ergebnis ist hier.

array(4) {
  ["should be"]=>
  string(12) "6FCC8861CC8A"
  ["grapheme"]=>
  string(12) "6FCC8861CC8A"
  ["mbstring"]=>
  string(12) "CC886FCC8A61"
  ["pcre"]=>
  string(12) "CC886FCC8A61"
}

Intlbreakiterator kann seit PHP 5.5 (INTL 3.0) verwendet werden;

function utf8_strrev($str)
{
    $it = IntlBreakIterator::createCodePointInstance();
    $it->setText($str);

    $ret = '';
    $pos = 0;
    $prev = 0;

    foreach ($it as $pos) {
        $ret = substr($str, $prev, $pos - $prev) . $ret;
        $prev = $pos;
    }

    return $ret;  
}

Andere Tipps

Hier ist ein weiterer Ansatz mit Regex:

function utf8_strrev($str){
 preg_match_all('/./us', $str, $ar);
 return implode(array_reverse($ar[0]));
}

Hier ist ein anderer Weg. Dies scheint zu funktionieren, ohne eine Ausgangscodierung angeben zu müssen (getestet mit einigen verschiedenen mb_internal_encodings):

function mb_strrev($text)
{
    return join('', array_reverse(
        preg_split('~~u', $text, -1, PREG_SPLIT_NO_EMPTY)
    ));
}

Die Antwort

function mb_strrev($text, $encoding = null)
{
    $funcParams = array($text);
    if ($encoding !== null)
        $funcParams[] = $encoding;
    $length = call_user_func_array('mb_strlen', $funcParams);

    $output = '';
    $funcParams = array($text, $length, 1);
    if ($encoding !== null)
        $funcParams[] = $encoding;
    while ($funcParams[1]--) {
         $output .= call_user_func_array('mb_substr', $funcParams);
    }
    return $output;
}

Eine andere Methode:

function mb_strrev($str, $enc = null) {
    if(is_null($enc)) $enc = mb_internal_encoding();
    $str = mb_convert_encoding($str, 'UTF-16BE', $enc);
    return mb_convert_encoding(strrev($str), $enc, 'UTF-16LE');
}

Es ist leicht utf8_strrev( $str ). Siehe die Relevanten Quelle Code meiner Bibliothek, den ich unten kopierte:

function utf8_strrev( $str )
{
    return implode( array_reverse( utf8_split( $str ) ) );
}

function utf8_split( $str , $split_length = 1 )
{
    $str    = ( string ) $str;

    $ret    = array( );

    if( pcre_utf8_support( ) )
    {
        $str    = utf8_clean( $str );

        $ret    = preg_split('/(?<!^)(?!$)/u', $str );

        // \X is buggy in many recent versions of PHP
        //preg_match_all( '/\X/u' , $str , $ret );
        //$ret  = $ret[0];
    }
    else
    {
        //Fallback

        $len    = strlen( $str );

        for( $i = 0 ; $i < $len ; $i++ )
        {
            if( ( $str[$i] & "\x80" ) === "\x00" )
            {
                $ret[]  = $str[$i];
            }
            else if( ( ( $str[$i] & "\xE0" ) === "\xC0" ) && ( isset( $str[$i+1] ) ) )
            {
                if( ( $str[$i+1] & "\xC0" ) === "\x80" )
                {
                    $ret[]  = $str[$i] . $str[$i+1];

                    $i++;
                }
            }
            else if( ( ( $str[$i] & "\xF0" ) === "\xE0" ) && ( isset( $str[$i+2] ) ) )
            {
                if( ( ( $str[$i+1] & "\xC0" ) === "\x80" ) && ( ( $str[$i+2] & "\xC0" ) === "\x80" ) )
                {
                    $ret[]  = $str[$i] . $str[$i+1] . $str[$i+2];

                    $i  = $i + 2;
                }
            }
            else if( ( ( $str[$i] & "\xF8" ) === "\xF0" ) && ( isset( $str[$i+3] ) ) )
            {
                if( ( ( $str[$i+1] & "\xC0" ) === "\x80" ) && ( ( $str[$i+2] & "\xC0" ) === "\x80" ) && ( ( $str[$i+3] & "\xC0" ) === "\x80" ) )
                {
                    $ret[]  = $str[$i] . $str[$i+1] . $str[$i+2] . $str[$i+3];

                    $i  = $i + 3;
                }
            }
        }
    }


    if( $split_length > 1 )
    {
        $ret = array_chunk( $ret , $split_length );

        $ret    = array_map( 'implode' , $ret );
    }

    if( $ret[0] === '' )
    {
        return array( );
    }

    return $ret;
}


function utf8_clean( $str , $remove_bom = false )
{
    $regx = '/([\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3})|./s';

    $str    = preg_replace( $regx , '$1' , $str );

    if( $remove_bom )
    {
        $str    = utf8_str_replace( utf8_bom( ) , '' , $str );
    }

    return $str;
}


function utf8_str_replace( $search , $replace , $subject , &$count = 0 )
{
    return str_replace( $search , $replace , $subject , $count );
}


function utf8_bom( )
{
    return "\xef\xbb\xbf";

}


function pcre_utf8_support( )
{
    static $support;

    if( !isset( $support ) )
    {
        $support = @preg_match( '//u', '' );
        //Cached the response
    }

    return $support;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top