我有一个PHP 函数,输入两个变量,分别为宽度和文本串。它会计算根据输入指定的宽度,该文本串可以分成多少行显示。这个函数能支持英文文本串,为啥输入中文就会报编码错误呢 NbLines Malformed UTF-8 characters, possibly incorrectly encoded 。 如何修改能让它 $txt 既支持英文又支持中文呢。
function NbLines($w, $txt)
{
// Compute the number of lines a MultiCell of width w will take
if (!isset($this->CurrentFont))
$this->Error('No font has been set');
$cw = $this->CurrentFont['cw'];
if ($w == 0)
$w = $this->w - $this->rMargin - $this->x;
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', (string)$txt);
$nb = strlen($s);
if ($nb > 0 && $s[$nb - 1] == "\n")
$nb--;
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = $s[$i];
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ')
$sep = $i;
$l += $cw[$c];
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j)
$i++;
} else
$i = $sep + 1;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else
$i++;
}
return $nl;
}
该回答引用ChatGPT
如有疑问,可以回复我!
问题是因为您的函数中使用了 strlen 和数组索引的方式,这样只支持单字节编码字符,如英文。对于多字节编码的字符,如中文,这种方式会导致错误。为了解决这个问题,您需要使用 mb_strlen 和 mb_substr 函数,它们是多字节字符串函数,支持多字节字符,如中文。以下是修改后的 NbLines 函数:
function NbLines($w, $txt)
{
// Compute the number of lines a MultiCell of width w will take
if (!isset($this->CurrentFont))
$this->Error('No font has been set');
$cw = $this->CurrentFont['cw'];
if ($w == 0)
$w = $this->w - $this->rMargin - $this->x;
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', (string)$txt);
$nb = mb_strlen($s, 'UTF-8');
if ($nb > 0 && $s[$nb - 1] == "\n")
$nb--;
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = mb_substr($s, $i, 1, 'UTF-8');
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ')
$sep = $i;
if (isset($cw[$c])) {
$l += $cw[$c];
} else {
$l += 500; // 使用一个默认宽度,或者您可以根据需要设置一个更合适的值
}
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j)
$i++;
} else
$i = $sep + 1;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else
$i++;
}
return $nl;
}
参考GPT和自己的思路:这个错误提示表明您的文本串包含不正确编码的UTF-8字符。中文字符通常需要占用多个字节,如果这些字节不正确地编码,就会导致该错误。您可以尝试在处理文本串之前使用 mb_detect_encoding() 函数检测文本串的编码,如果它不是UTF-8,则可以使用 mb_convert_encoding() 函数将其转换为UTF-8编码。将以下代码添加到您的函数中可能会有所帮助:
// Check and convert encoding to UTF-8 if necessary
if (mb_detect_encoding($txt, 'UTF-8', true) === false) {
$txt = mb_convert_encoding($txt, 'UTF-8');
}
这将检查输入的 $txt 是否为 UTF-8 编码,如果不是,就将其转换为 UTF-8 编码。这将确保 $txt 中的中文字符正确地编码,可以被函数正确处理。
参考GPT和自己的思路:
这个问题是因为PHP默认使用ASCII编码,而中文字符是多字节字符,所以需要使用UTF-8编码。建议在函数开头增加以下代码:
$txt = mb_convert_encoding($txt, 'UTF-8', 'auto');
此外,还需要确保调用函数时$txt的编码也是UTF-8。要么将$txt直接赋值为UTF-8编码字符串,要么在调用函数前将$txt转换为UTF-8。
参考GPT和自己的思路:
问题的原因在于该函数中的字符串在处理中文字符时出现了编码错误。为了支持中文文本串,需要对函数进行修改。应该首先确认输入的文本串的编码格式,例如UTF-8或者GB2312。然后在函数中使用相应的编码函数进行字符串的处理,如iconv()或mb_convert_encoding()函数。同时,需要修改函数中的字符长度处理部分,因为中文字符的长度并不是单个字符的长度,而是需要考虑字节数的情况。最后,需要确保输出的结果也使用相应的编码格式。
参考GPT和自己的思路,该函数在处理中文时报编码错误是因为它使用了PHP内置的字符串函数,而这些函数默认假设字符串是UTF-8编码。在处理中文时,如果文本串不是UTF-8编码的,那么就会出现编码错误。
为了让该函数既支持英文又支持中文,你需要确保输入的文本串是UTF-8编码的。可以使用mb_convert_encoding()函数将输入的文本串转换成UTF-8编码,示例代码如下:
function NbLines($w, $txt)
{
// Convert the text to UTF-8 encoding
$txt = mb_convert_encoding($txt, 'UTF-8', 'auto');
// Rest of the function code remains the same...
}
在这个修改后的函数中,我们将输入的文本串使用mb_convert_encoding()函数进行了转换,将它从自动检测的编码转换为UTF-8编码。这样就可以确保字符串是UTF-8编码,从而避免编码错误。
哥哥这个函数报错的原因是中文字符串的编码格式不是UTF-8,需要将其转换为UTF-8格式后再进行处理。可以使用PHP内置的iconv函数来完成这个任务,如下所示:
function NbLines($w, $txt)
{
// Convert the string to UTF-8
$txt = iconv('GBK', 'UTF-8', $txt);
// Compute the number of lines a MultiCell of width w will take
if (!isset($this->CurrentFont))
$this->Error('No font has been set');
$cw = $this->CurrentFont['cw'];
if ($w == 0)
$w = $this->w - $this->rMargin - $this->x;
$wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
$s = str_replace("\r", '', (string)$txt);
$nb = strlen($s);
if ($nb > 0 && $s[$nb - 1] == "\n")
$nb--;
$sep = -1;
$i = 0;
$j = 0;
$l = 0;
$nl = 1;
while ($i < $nb) {
$c = $s[$i];
if ($c == "\n") {
$i++;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
continue;
}
if ($c == ' ')
$sep = $i;
$l += $cw[$c];
if ($l > $wmax) {
if ($sep == -1) {
if ($i == $j)
$i++;
} else
$i = $sep + 1;
$sep = -1;
$j = $i;
$l = 0;
$nl++;
} else
$i++;
}
return $nl;
}
在上面的代码中,我们首先使用iconv函数将$txt变量从GBK编码格式转换为UTF-8编码格式,然后再按照原来的逻辑计算多行显示时的行数。这样就可以支持中文字符串变量了。
举个例子:
iconv("GB2312","UTF-8",$a);
解决办法,将GB2312更改为GBK即可搞定:
iconv("GBK","UTF-8",$a);
出现这个错误的原因是字符串$a中出现了超出gb2312范围的字符,所以iconv函数出错。因为gbk范围比gb3212范围广,又因为这两种格式的编码相同只是范围不同而已,故采用大范围的gbk来定义字符串能够包含比较多的字符,因此转化成功