目前,我不明白为什么在处理UTF-8时在PHP中使用mbstring函数非常重要?我在linux下的语言环境已经设置为UTF-8,那么为什么默认情况下strlen
,preg_replace
等函数不能正常工作?
答案 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个字节。
答案 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作为b
和b1
作为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进行说明。