为什么这个 str_ireplace() 函数能够处理非 ASCII 字符串?

7

注意: 我认为我知道的可能是错误的,所以请您帮忙纠正我的知识 :)


我刚刚回答了一个关于UTF-8和PHP的问题。

我建议使用str_ireplace('Волгоград', '', $a)

我没想到这会起作用,但它确实起作用了。

我一直以为PHP将一个字节视为一个字符,因此当使用ASCII范围之外的字符时,需要使用mb_*函数才能获得准确的结果。

我假设俄语字符每个都需要> 1个字节。

我认为str_replace()会起作用,因为无论是否为多字节,只要按顺序匹配字节即可。

我认为str_ireplace()不会起作用,因为PHP不知道如何将非ASCII字符映射到它们的大写等效项。但是,它确实起作用了。


我在哪里错了?请尽可能提供更多信息 :)


我本想宣布你已启用了 mbstring.func_overload。但根据文档,它不应该掩盖 str_ireplace。(或者它只是没有记录在案。) - mario
@mario 我的 mbstring.func_overload 已关闭。 - alex
3个回答

6

它通过将文本传递给依赖于区域设置的libc函数,使文本变为小写;适当的设置意味着如果使用正确的字符集用于字节,则文本将正确地变为小写。


PHP本身不负责将文本转换为小写;它委托给libc(glibc、MSVCRT等)来执行适当的小写操作。PHP将其视为一系列字节,这在大多数情况下并不重要,因为链中的某个人知道他们在做什么。 - Ignacio Vazquez-Abrams

3

另一个可能的解释是,Unicode平面与ISO-8859-1范围具有类似的属性。

将大写字母转换为小写字母只需要在ASCII范围内加上0x20

0x41   A
0x61   a

-我没有去查- 我认为在0xC0-0xDF的Latin-1范围内也是一样的。这巧合地适用于Unicode范围内的俄语字母:

d092d09ed09bd093d09ed093d0a0d090d094   ВОЛГОГРАД
d0b2d0bed0bbd0b3d0bed0b3d180d0b0d0b4   волгоград

区别只在于在被认为是L1字符的字节上添加了0x20。因此,这可能只是一种区域设置。


谢谢Mario,尽管我觉得我还有很多需要学习的地方。但是我的上述陈述中是否有任何错误呢? - alex
但是要知道它应该保留UTF-8多字节序列的第一个字节,它必须意识到字符串实际上是多字节的。或者我错了吗? - Stefan Gehrig
@alex:这是一个令人困惑的话题。只有检查C源代码才能澄清。我认为这里是一个偶然的函数。PHP字符串函数不知道多字节,所以要么它真的是像Ignacio说的那样的libc函数,要么就是意外的0x20处理在这里起作用了。 - mario
@Stefan:确实不是。 这里的错误在于我假设 0xD0 Unicode 范围前缀保持原样。只有 0x9x 字节会被转换。ISO-8859-1 小写处理是按字节进行的,会跳过无关内容。这里第二个多字节字符被忽略了。 - mario

0

事实上是相反的:PHP并不将每个字符视为一个字节,而是将每个字节视为一个字符。因此,多个字符被视为多个字符(可能不是您期望的那个字符)。


谢谢。那就是我想说的 :P - alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接