11

目前,我不明白为什么在处理 UTF-8 时在 PHP 中使用 mbstring 函数真的很重要?strlen我在linux下的locale已经设置为UTF-8了,那么为什么preg_replace默认情况下不能正常工作呢?

4

6 回答 6

15

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

来自多字节字符串介绍

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

于 2011-07-17T06:32:26.543 回答
7

这里的人不懂UTF-8。

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

我什至编写了 Unicode 大写/小写,以及 NFC 和 NFD 转换,只使用字节感知函数。很难想出比这更复杂的事情了,需要对 UTF-8 进行如此细致而细致的处理。然而它仍然适用于纯字节函数。

很少需要 UTF-8 感知代码。也许要计算字符数,或者将插入点向前移动 1 个字符。但实际上,即使那样你的代码也不会工作;)因为分解的字符。

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

我会解释为什么。

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

试着向我解释一下如何在多字节系统中出现文本处理错误,在另一个字符中找不到字符?仅举一例!你能想到的最简单的。

于 2011-07-17T14:27:03.693 回答
6

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

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

于 2011-07-17T06:33:32.920 回答
2

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

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

现在,只要对字符串做基本的处理,根本不需要知道字符编码。因此,如果您想使用 将字符串存储回文件中,file_put_contents()或者想要使用 获取其长度(而不是字符数strlen(),那么您就可以了。

但是,一旦您开始进行更多花哨的字符串操作,您就需要知道字符编码!无法将其存储为字符串的一部分,因此您要么必须单独跟踪它,要么像大多数人所做的那样,使用将所有(文本)字符串采用通用字符编码的约定,如 US-ASCII 或现在 UTF-8

因此,由于无法为字符串设置字符编码,PHP 不知道字符串使用的是哪种字符编码。因此,唯一明智的strlen()做法是返回字节数,因为这是 PHP 唯一确定的事情。

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

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

因此,如果您有一个假设的字符编码,它编码一个小写aasa1和一个大写Aas a2、 a basb1Bas b2(等等),您可以有一个(编码的)字符串a1a1a1,它由三个相同的字符连续组成. 但是,如果不知道编码并且仅查看字节序列,则无法检测到这一点。

概括:

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

这就是函数重载特性本质上被破坏的原因,即使它一开始看起来不错,也会以难以调试的方式破坏你的代码。

于 2017-01-08T00:22:21.827 回答
0

多字节 => 多 + 字节。

1)它用于处理其他语言(不是英文)格式的字符串。

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

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

,以便引入mbstring用于与各种语言(如中文、日文等)进行通信。

于 2016-07-22T19:08:24.980 回答
0

劳尔·冈萨雷斯 (Raul González) 是一个完美的例子,说明了原因:

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

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

一般错误:1366 不正确的字符串值:第 1 行的列“名称”的“\xC3”(SQL:更新usersname= Raul Gonz▒,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 用于说明。

于 2019-03-04T04:40:10.940 回答