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

问题描述 投票:9回答:6

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

php utf-8 multibyte
6个回答
13
投票

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

来自Multibyte String Introduction

当您操作(修剪,拆分,拼接等)以多字节编码编码的字符串时,您需要使用特殊函数,因为在此类编码方案中,两个或多个连续字节可能表示单个字符。否则,如果您对字符串应用非多字节感知字符串函数,它可能无法检测到多字节字符的开头或结尾,并最终导致损坏的垃圾字符串很可能失去其原始含义。


6
投票

这里的人不懂UTF-8。

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

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

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

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

我会解释原因。

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

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


4
投票

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

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


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作为a2b编码为b1B作为b2(依此类推),你可以有一个(编码的)字符串a1a1a1它由一行中的三个相同字符组成。但是,在不知道编码的情况下,只需查看字节序列,就无法检测到这种情况。

摘要:

由于PHP字符串不包含字符编码,因此没有理智的“默认”。即使像strlen()这样的单个函数也不能返回Content-Length HTTP头所​​需的字节序列长度,同时字符数也可以表示博客文章的长度。

这就是为什么Function Overloading Feature本身就被破坏了,即使它一开始看起来不错,也会以难以调试的方式破坏你的代码。


0
投票

multibyte => multi + byte。

1)用于使用其他语言(不是英语)格式的字符串。 2)默认的PHP字符串函数只适用于英语(或与之相关)语言。 3)如果你想使用strlen()或strpos()或uppercase()或strreplace()来表示特殊字符, 假设我们需要在“Hello”上应用字符串函数。 在中国(你好),阿拉伯语(مرحبا),日语(こんにちは),印地语(नमस्ते),古吉拉特语(હેલો)。 不同的语言可以是自己的角色集 因此引入了mbstring用于与各种语言(如中文,日语等)进行通信。


0
投票

RaulGonzález是一个完美的例子:

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

下面的单元测试是一个如何得到这样的错误的示例

一般错误:1366字符串值不正确:第1行第'name'列的'\ xC3'(SQL:update users set 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用于说明。

© www.soinside.com 2019 - 2024. All rights reserved.