为什么在PHP中使用多字节字符串函数?

时间:2011-07-17 06:22:56

标签: php utf-8 multibyte

目前,我不明白为什么在处理UTF-8时在PHP中使用mbstring函数非常重要?我在linux下的语言环境已经设置为UTF-8,那么为什么默认情况下strlenpreg_replace等函数不能正常工作?

6 个答案:

答案 0 :(得分:13)

无论您的操作系统的语言环境如何,所有PHP string functions都不会处理多字节字符串。这就是你需要使用多字节字符串函数的原因。

来自Multibyte String Introduction

  

当您操纵(修剪,分割,拼接等)编码的字符串时   多字节编码,你需要使用特殊功能,因为两个或   更多连续字节可以代表这样的单个字符   编码方案。否则,如果您应用非多字节感知字符串   函数到字符串,它可能无法检测到开头或   多字节字符的结尾,最后是一个损坏的垃圾   字符串很可能失去其原始含义。

答案 1 :(得分:6)

这里的人不懂UTF-8。

您不需要使用UTF-8识别代码来处理UTF-8。在大多数情况下。

我甚至只使用字节感知功能编写了Unicode大写/小写,NFC和NFD变换。很难想到比这更复杂的东西,需要对UTF-8进行如此细致和细致的处理。然而它仍然适用于仅字节函数。

您需要支持UTF-8的代码非常罕见。也许计算字符数,或将插入点向前移动1个字符。但实际上,即使这样你的代码也无法工作;)因为分解了字符。

但如果您所做的只是替换,查找内容,甚至解析语法,您只需要字节感知功能。

我会解释原因。

这是因为在任何其他UTF-8字符中都找不到UTF-8字符。这就是它的设计方式。

尝试向我解释如何在多字节系统中找到文本处理错误,在多字节系统中,在另一个字符中找不到字符?只是一个例子!你能想到的最简单。

答案 2 :(得分:4)

这是我用简单的英语回答的。 单个日文,中文和韩文字符占用多个字节。例如,一个典型的charactert说x在英语中占用1个字节,在日语,中文和韩语中需要超过1个字节。现在,PHP的标准字符串函数用于将单个字符视为1个字节。因此,如果您尝试比较两个日文或中文或韩文字符,它们将无法按预期工作。例如“Hello World!”的长度。日语,中文或韩语将超过12个字节。

阅读http://www.php.net/manual/en/intro.mbstring.php

答案 3 :(得分:1)

PHP字符串只是普通的字节序列。他们自己没有任何意义。并且它们也不使用任何特定的字符编码。

因此,如果您使用file_get_contents()读取文件,则会获得该文件的二进制安全表示。可能是图像或人类可读文本文件的(二进制)表示 - PHP并不关心。

现在,只要你只需要对字符串进行基本处理,就根本不需要知道字符编码。因此,如果您想使用file_put_contents()将字符串存储回文件中,或者希望使用strlen()获取其长度(不是字符数),那么您没问题。

然而,一旦你开始做更多花哨的字符串操作,你需要知道字符编码!无法将其存储为字符串的一部分,因此您必须单独跟踪它,或者大多数人都这样做,使用通用字符编码中包含所有(文本)字符串的约定,如US -ASCII或现在的UTF-8

因为没有办法为字符串设置字符编码, PHP不知道字符串使用哪个字符编码。因此,strlen()唯一能做的就是返回字节数,因为这是PHP确实知道的唯一事情。

如果您提供使用的字符编码的附加信息,则需要使用另一个函数 - 在这种情况下,该函数称为mb_strlen()

同样适用于preg_replace():如果你想要替换umlaut-a,或者连续匹配三个相同的字符,你需要知道umlaut-a是如何编码的,一般来说,是如何编码字符的

因此,如果你有一个假设的字符编码,它将小写a编码为a1,将大写A编码为a2,则{{1作为bb1作为B(依此类推),您可以拥有一个(编码的)字符串b2,该字符串由一行中的三个相同字符组成。但是,在不知道编码的情况下,只需查看字节序列,就无法检测到它。

要点:

由于PHP字符串不包含字符编码,因此无法理解'默认'。即使像a1a1a1这样的单个函数无法返回strlen() HTTP标头和同时所需的字节序列长度,对于有用的字符数也是如此。表示博客文章的长度。

这就是Function Overloading Feature本来就被破坏的原因,即使它一开始看起来很好,也会以难以调试的方式破坏你的代码。

答案 4 :(得分:0)

  

multibyte =>多+字节。

1)用于使用其他语言(不是英语)格式的字符串。

2)默认的PHP字符串函数只适用于英语(或与之相关)语言。

3)如果要使用strlen()或strpos()或uppercase()或strreplace()作为特殊字符,
假设我们需要在“Hello”上应用字符串函数 在中国(你好),阿拉伯语(مرحبا),日语(こんにちは),印地语( नमस्ते),古吉拉特语(હેલો)。
不同的语言可以是自己的字符集

因此引入了mbstring用于与各种语言(如中文,日语等)进行通信。

答案 5 :(得分:0)

劳尔·冈萨雷斯(RaulGonzález)是一个很好的例子,说明了为什么:

这是关于缩短MySQL数据库的用户名,例如我们限制10个字符和Raul González

下面的单元测试是一个如何获取此类错误的示例

  

一般错误:1366错误的字符串值:第1行的“名称”列的“ \ xC3”(SQL:更新users设置name = RaulGonz▒,updated_at = 2019 -03-04 04:28:46其中id = 793)

以及如何避免它

public function test_substr(): void
{
    $name = 'Raul González';
    $user = factory(User::class)->create(['name' => $name]);
    try {
        $name1      = substr($name, 0, 10);
        $user->name = $name1;
        $user->save();
    } catch (Exception $ex) {

    }
    $this->assertTrue(isset($ex));

    $name2      = mb_substr($name, 0, 10);
    $user->name = $name2;
    $user->save();

    $this->assertTrue(true);
}

使用PHP Laravel和PhpUnit进行说明。