【问题标题】:Why do some characters lose when I use str_shuffle() in PHP?为什么我在 PHP 中使用 str_shuffle() 会丢失一些字符?
【发布时间】:2013-09-10 12:35:38
【问题描述】:

这是lib.php中的代码:

<?php

class table {

    function __construct($string, $time) {

        $out = '<table cellpadding="5">';
        $out .= $this->getRow('th', 'Nom., Shuffled String, Lenght');

        for ($x = 1; $x <= $time; $x++) {

            $shuffledStr = str_shuffle($string); //Maybe this causes the problem
            $shuffledStr_len = strlen($shuffledStr);
            $out .= $this->getRow('td', $x . ', ' . $shuffledStr . ', ' . $shuffledStr_len);
        }

        $out .= '</table>';

        echo $out;
    }

    public function getRow($tagName, $contents_list) {

        //Variables:
        $out = '';
        $contents_array = explode(', ', $contents_list);
        $contents_number = count($contents_array);
        $start_tag = '<' .  $tagName . '>';
        $end_tag = '</' .   $tagName . '>';

        // Build
        $out .= '<tr>';

        for ($i = 0; $i < $contents_number; $i++) {
            $out .= $start_tag . $contents_array[$i] . $end_tag;
        }

        $out .= '</tr>';

        return $out;
    }

}
?>

这里是 index.php:

    <?php
require_once 'lib.php';
$string = ''; //My string
$shuffleTimes = 100;
$table = new table($string, $shuffleTimes);
?>

这个程序得到一个字符串和你想洗牌的数字, 然后创建一个表并返回每行中的数字、洗牌字符串和洗牌字符串的长度。

例如,如果我将变量 $string 设置为“堆栈溢出”,它会正常工作(它随机打乱这个词 100 次,返回所有长度 14 并且 ALL 的长度被打乱字符串实际上是 14。)

但是……

如果我向变量$string(例如Stack Overflow+_)(*&amp;^%$#{}[]&lt;&gt;@!~./=-)添加一些特殊字符,它将无法正常工作。这意味着它返回长度 37 但它们没有 37 个字符!(例如,它打印 nothing 并打印它的长度 38。 我觉得这有点奇怪。 :(

这是为什么?!是哪个角色造成的,如何解决?

【问题讨论】:

  • Stack Overflow+_)(*&amp;^%$#{}[]&lt;&gt;@!~./=- 是 37 个字符长度...?
  • 是的。不是吗?
  • 你说But they doesn't have 37 characters!。现在怎么办?有没有37? p.s.你的代码对我有用。它只对多字节字符不起作用。
  • 它返回 NOTHING 并且还返回它有 37 个字符。什么是“多字节”字符?能解释一下或者给个链接吗?

标签: php string special-characters shuffle


【解决方案1】:

您的代码存在多个问题。

1。 getRow() 问题:

问题出在getRow(),您将参数与, 连接成一个字符串,然后由, 分解。如果你的字符串里面有,,那么你就会遇到问题,例如:Stack ,test

2。多字节问题:

此代码不适用于多字节字符。为此,您需要将函数str_shuffle() 更改为mb_str_shuffle(),并将strlen() 更改为mb_strlen()

function mb_str_shuffle($str) {
    $tmp = preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
    shuffle($tmp);
    return join("", $tmp);
}

或者您在 http://php.net/manual/en/function.str-shuffle.php 上的 cmets 中找到的其他一些 unicode 函数

3。长度没问题,但字符串丢失问题:

这是因为您的字符串中有 HTML 特殊字符,例如 &lt;&gt;。如果字符串Stack Overflow+_)(*&amp;^%$#{}[]&lt;&gt;@!~./=- 被打乱,你得到类似a#^&amp;/c-_O. 而不是a#^&amp;/c-_O.&lt; ~*&gt;)$wevS+{(%}klr[]f=to!@。输出字符串时应使用htmlspecialchars() 转义特殊字符。

【讨论】:

  • 感谢您对htmlspecialchars()的提醒。字符串应该在没有转义的情况下处理,因为转义会增加字符串的长度。字符串必须在显示之前进行转义。 (问题出现在 lib.php 的第 14 行,它应该更改为 ` $out .= $this->getRow('td', $x . ', ' . htmlspecialchars($shuffledStr) . ', ' . $shuffledStr_len) ;` 已解决 :)
【解决方案2】:

听起来像是编码的问题。

您是否尝试过使用正确处理编码的函数?

试试这个:(复制自 PHP 手册)

function unicode_shuffle($string, $chars, $format = 'UTF-8')
{
    for($i=0; $i<$chars; $i++)
        $rands[$i] = rand(0, mb_strlen($string, $format));

        $s = NULL;

    foreach($rands as $r)
        $s.= mb_substr($string, $r, 1, $format);

    return $s;
}

【讨论】:

  • 不,这不起作用。如果需要,请执行以下操作: function unicode_shuffle($string, $chars, $format = 'UTF-8') { return mb_substr(str_shuffle_unicode($string), 0, $chars, $format); }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多