目前,我不明白为什么在处理UTF-8时在PHP中使用mbstring函数非常重要?我在linux下的语言环境已经设置为UTF-8,那么为什么strlen
,preg_replace
等函数默认不能正常工作?
无论您的操作系统的语言环境如何,所有PHP string functions都不会处理多字节字符串。这就是您需要使用多字节字符串函数的原因。
来自Multibyte String Introduction:
当您操作(修剪,拆分,拼接等)以多字节编码编码的字符串时,您需要使用特殊函数,因为在此类编码方案中,两个或多个连续字节可能表示单个字符。否则,如果您对字符串应用非多字节感知字符串函数,它可能无法检测到多字节字符的开头或结尾,并最终导致损坏的垃圾字符串很可能失去其原始含义。
这里的人不懂UTF-8。
您不需要使用UTF-8感知代码来处理UTF-8。在大多数情况下。
我甚至只使用字节感知功能编写了Unicode大写/小写,NFC和NFD变换。很难想到比这更复杂的东西,需要对UTF-8进行如此细致和细致的处理。但它仍然适用于仅字节函数。
您需要UTF-8感知代码是非常罕见的。也许计算字符数,或将插入点向前移动1个字符。但实际上,即使这样你的代码也无法工作;)因为分解了字符。
但是,如果您所做的只是替换,查找内容,甚至解析语法,您只需要字节感知功能。
我会解释原因。
这是因为在任何其他UTF-8字符中都找不到UTF-8字符。这就是它的设计方式。
尝试向我解释如何在多字节系统中获取文本处理错误,在多字节系统中,在另一个字符中找不到字符?只是一个例子!你能想到的最简单。
这是我用简单的英语回答的。单个日文,中文和韩文字符占用多个字节。例如,一个典型的charactert说x
在英语中占用1个字节,它将需要比日语,中文和韩语更多的1
字节。现在,PHP的标准字符串函数用于将单个字符视为1个字节。因此,如果您尝试比较两个日文或中文或韩文字符,它们将无法按预期工作。例如“Hello World!”的长度。日语,中文或韩语将超过12个字节。
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
,b
编码为b1
和B
作为b2
(依此类推),你可以有一个(编码的)字符串a1a1a1
它由一行中的三个相同字符组成。但是,在不知道编码的情况下,只需查看字节序列,就无法检测到这种情况。
摘要:
由于PHP字符串不包含字符编码,因此没有理智的“默认”。即使像strlen()
这样的单个函数也不能返回Content-Length
HTTP头所需的字节序列长度,同时字符数也可以表示博客文章的长度。
这就是为什么Function Overloading Feature本身就被破坏了,即使它一开始看起来不错,也会以难以调试的方式破坏你的代码。
multibyte => multi + byte。
1)用于使用其他语言(不是英语)格式的字符串。 2)默认的PHP字符串函数只适用于英语(或与之相关)语言。 3)如果你想使用strlen()或strpos()或uppercase()或strreplace()来表示特殊字符, 假设我们需要在“Hello”上应用字符串函数。 在中国(你好),阿拉伯语(مرحبا),日语(こんにちは),印地语(नमस्ते),古吉拉特语(હેલો)。 不同的语言可以是自己的角色集 因此引入了mbstring用于与各种语言(如中文,日语等)进行通信。
RaulGonzález是一个完美的例子:
它是关于缩短MySQL数据库的太长用户名,比如我们有10个字符限制和Raul González
。
下面的单元测试是一个如何得到这样的错误的示例
一般错误:1366字符串值不正确:第1行第'name'列的'\ xC3'(SQL:update
users
setname
=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用于说明。