2013-02-08 11 views
9

Ich versuche nur, die $str auf 5 Zeichen zu fixieren, konnte aber nicht.PHP, str_pad Unicode-Ausgabe

$str = "nü"; 
echo str_pad($str, 5, "ü"); // give nüü 

Ich weiß, das ist ein Unicode-Problem und suchte viel, aber kein Glück. Ich habe versucht, etwas wie;

echo str_pad($str, 4 + mb_strlen($s), $s); 
echo str_pad($str, 5 + mb_strlen($s), $s); 

Auch habe ich versucht, diese http://www.php.net/manual/de/function.str-pad.php#89754 und sah diese https://stackoverflow.com/a/11871948/362780.

Irgendwelche Erfahrungen zu diesem Thema?

Danke.

+0

FWIW, ich habe meine Antwort auf eine robustere Version des Algorithmus aktualisiert, genommen direkt aus dem Quellcode von PHP selbst :) –

Antwort

3

Ich glaube, Sie müssen innen mehr php.net sehen (hier: http://php.net/str_pad#111147). Aber ich habe es ein bisschen verändert.

Hinweis: Vergessen Sie nicht, dies vorher unter mb_internal_encoding("utf-8"); anzurufen.

mb_internal_encoding("utf-8"); 

function str_pad_unicode($str, $pad_len, $pad_str = ' ', $dir = STR_PAD_RIGHT) { 
    $str_len = mb_strlen($str); 
    $pad_str_len = mb_strlen($pad_str); 
    if (!$str_len && ($dir == STR_PAD_RIGHT || $dir == STR_PAD_LEFT)) { 
     $str_len = 1; // @debug 
    } 
    if (!$pad_len || !$pad_str_len || $pad_len <= $str_len) { 
     return $str; 
    } 

    $result = null; 
    if ($dir == STR_PAD_BOTH) { 
     $length = ($pad_len - $str_len)/2; 
     $repeat = ceil($length/$pad_str_len); 
     $result = mb_substr(str_repeat($pad_str, $repeat), 0, floor($length)) 
       . $str 
       . mb_substr(str_repeat($pad_str, $repeat), 0, ceil($length)); 
    } else { 
     $repeat = ceil($str_len - $pad_str_len + $pad_len); 
     if ($dir == STR_PAD_RIGHT) { 
      $result = $str . str_repeat($pad_str, $repeat); 
      $result = mb_substr($result, 0, $pad_len); 
     } else if ($dir == STR_PAD_LEFT) { 
      $result = str_repeat($pad_str, $repeat); 
      $result = mb_substr($result, 0, 
         $pad_len - (($str_len - $pad_str_len) + $pad_str_len)) 
        . $str; 
     } 
    } 

    return $result; 
} 

$t = STR_PAD_LEFT; 
$s = '...'; 
$as = 'AO'; 
$ms = 'ÄÖ'; 
echo "<pre>\n"; 
for ($i = 3; $i <= 1000; $i++) { 
    $s1 = str_pad($s, $i, $as, $t); // can not inculde unicode char!!! 
    $s2 = str_pad_unicode($s, $i, $ms, $t); 
    $l1 = strlen($s1); 
    $l2 = mb_strlen($s2); 
    echo "len $l1: $s1 \n"; 
    echo "len $l2: $s2 \n"; 
    echo "\n"; 
    if ($l1 != $l2) die("Fail!"); 
} 
echo "</pre>"; 

Test hier: http://codepad.viper-7.com/3jTEgt

+0

Sollte '' '$ repeat = ceil ($ str_len - $ pad_str_len + $ pad_len); '' 'nicht' '$ $ repeat = ceil (($ str_len - $ pad_len)/$ pad_str_len);' ''? Ihre Version funktioniert, ist aber etwas ineffizient – user23127

+0

das sieht in der Tat ineffizient aus: PI hat ein einfacheres geschrieben, schau es dir an, ich habe es gerade gepostet – Wes

0

Versuchen Sie dies (es wie das aussehen kann dass nicht, aber das hat auch eine Codierung Prüfung):

<?php 
function mb_str_pad ($input, $pad_length, $pad_string, $pad_style, $encoding="UTF-8") { 
    return str_pad($input, strlen($input)-mb_strlen($input,$encoding)+$pad_length, $pad_string, $pad_style); 
} 
?> 

Source

+0

Es wäre fair hier einen Kommentar setzen nach Downvoting (wenn es war, weil ich die Quelle nicht angegeben habe, sorry und danke dafür, es für mich zu setzen). – beerwin

+2

Ich habe Sie nicht abgemeldet, obwohl es vielleicht downvoted wurde, weil der Code nicht wirklich funktioniert. –

4

Sie benötigen einen Multibyte-Version von str_pad(), wie unten. Es ist von der source code of str_pad() inspiriert.

function mb_str_pad($input, $pad_length, $pad_string = ' ', $pad_type = STR_PAD_RIGHT, $encoding = 'UTF-8') 
{ 
    $input_length = mb_strlen($input, $encoding); 
    $pad_string_length = mb_strlen($pad_string, $encoding); 

    if ($pad_length <= 0 || ($pad_length - $input_length) <= 0) { 
     return $input; 
    } 

    $num_pad_chars = $pad_length - $input_length; 

    switch ($pad_type) { 
     case STR_PAD_RIGHT: 
      $left_pad = 0; 
      $right_pad = $num_pad_chars; 
      break; 

     case STR_PAD_LEFT: 
      $left_pad = $num_pad_chars; 
      $right_pad = 0; 
      break; 

     case STR_PAD_BOTH: 
      $left_pad = floor($num_pad_chars/2); 
      $right_pad = $num_pad_chars - $left_pad; 
      break; 
    } 

    $result = ''; 
    for ($i = 0; $i < $left_pad; ++$i) { 
     $result .= mb_substr($pad_string, $i % $pad_string_length, 1, $encoding); 
    } 
    $result .= $input; 
    for ($i = 0; $i < $right_pad; ++$i) { 
     $result .= mb_substr($pad_string, $i % $pad_string_length, 1, $encoding); 
    } 

    return $result; 
} 


$str = "nü"; 
$pad = "ü"; 

echo mb_str_pad($str, 5, $pad); 
+0

Ich habe deinen Code getestet und 'mb_str_pad (" ... ", 4," ÄÖ ")' gibt '... ÄÖ', aber' str_pad_unicode ("...", 4, "ÄÖ") 'gibt'. .. € wie erwartet. –

+0

@qeremy Ich habe seine Funktion versucht und es funktioniert für mich. – Antony

+0

@Jack; Ich tat, aber das funktioniert nur für 'STR_PAD_RIGHT': http://codepad.viper-7.com/eXnyld –

13

Ein einfacher und effizienter ein. http://3v4l.org/UnXTF

<?php 

function mb_str_pad($str, $pad_len, $pad_str = ' ', $dir = STR_PAD_RIGHT, $encoding = NULL) 
{ 
    $encoding = $encoding === NULL ? mb_internal_encoding() : $encoding; 
    $padBefore = $dir === STR_PAD_BOTH || $dir === STR_PAD_LEFT; 
    $padAfter = $dir === STR_PAD_BOTH || $dir === STR_PAD_RIGHT; 
    $pad_len -= mb_strlen($str, $encoding); 
    $targetLen = $padBefore && $padAfter ? $pad_len/2 : $pad_len; 
    $strToRepeatLen = mb_strlen($pad_str, $encoding); 
    $repeatTimes = ceil($targetLen/$strToRepeatLen); 
    $repeatedString = str_repeat($pad_str, max(0, $repeatTimes)); // safe if used with valid unicode sequences (any charset) 
    $before = $padBefore ? mb_substr($repeatedString, 0, floor($targetLen), $encoding) : ''; 
    $after = $padAfter ? mb_substr($repeatedString, 0, ceil($targetLen), $encoding) : ''; 
    return $before . $str . $after; 
} 

// same random testing... 

foreach([STR_PAD_BOTH, STR_PAD_LEFT, STR_PAD_RIGHT] as $padType) 
{ 
    echo str_pad("FOO", 11, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOO", 11, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("FOO", 10, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOO", 10, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("BAAZ", 11, "aeo", $padType) . "\n"; 
    echo mb_str_pad("BAAZ", 11, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("BAAZ", 10, "aeo", $padType) . "\n"; 
    echo mb_str_pad("BAAZ", 10, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("FOOBAR", 6, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOOBAR", 6, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("FOOBAR", 1, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOOBAR", 1, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("FOOBAR", 0, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOOBAR", 0, "àèò", $padType, "UTF-8") . "\n"; 
    echo str_pad("FOOBAR", -10, "aeo", $padType) . "\n"; 
    echo mb_str_pad("FOOBAR", -10, "àèò", $padType, "UTF-8") . "\n"; 
    echo "--\n"; 
} 

?> 
+0

(obwohl das wahrscheinlich nicht so funktioniert, wie man es erwartet, wenn man Zeichen kombiniert) – Wes