在不使用u
标志的情况下,可以使用的十六进制范围是[\x{00}-\x{ff}]
,但是如果使用u
标志,则可以使用4字节值\x{7fffffff}
([\x{00000000}-\x{7fffffff}]
)。
因此,如果我执行以下代码:
preg_match("/[\x{00000000}-\x{80000000}]+/u", $str, $match);
将收到此错误
Warning: preg_match(): Compilation failed: character value in \x{...} sequence is too large
所以我不能匹配一个像这样的字母和等价的十六进制值f0 a1 83 81
。问题不是如何匹配这些字母,而是这个范围&这个边界来自as u
修饰符应该如何将字符串视为UTF-16
echo PCRE_VERSION;
使用PHP 5.3.24 - 5.3.28、5.4.14 -5.5.7的PCRE版本:
8.32 2012-11-30
带有PHP 5.3.19 - 5.3.23、5.4.9 -5.4.13的PCRE版本:
8.31 2012-07-06
发布于 2015-05-29 01:48:17
所以我不能将一个字母与f0 a1 83 81的十六进制值相匹配。问题不是如何匹配这些字母,而是这个范围&这个边界来自于u修饰符,应该如何将字符串视为UTF-16
您将两个概念混合在一起,这导致了这种混淆。
F0 A1 83 81
不是字符的十六进制值。这是UTF-8对字节流中该字符的码位进行编码的方式。
PHP支持\x{}
模式的UTF-16代码点是正确的,但是{
和}
中的值表示UTF-16代码点,而不是用于编码字节流中给定字符的实际字节。
因此,您可以在\x{}
中使用的最大值实际上是10FFFF
。
为了与PHP相匹配,你需要使用它的代码点,正如@minitech在他的评论中所建议的那样,它是\x{0210c1}
。
在PCRE documentation的"Validity of strings"一节中引用了进一步的解释。
在进行任何其他处理之前检查整个字符串。除了检查字符串的格式外,还会进行检查以确保所有代码点都在U+0到U+10FFFF的范围内,不包括代理区域。所谓的“非字符”代码点没有被排除在外,因为Unicode勘误#9清楚地表明它们不应该被排除在外。
Unicode的“代理区”中的字符保留供UTF-16使用,在UTF-16中,它们成对使用,以编码具有大于0xFFFF的值的代码点。由UTF-16对编码的代码点在UTF-8和UTF-32编码中独立可用。(换句话说,整个代理的事情是对UTF-16的捏造,它不幸地搞乱了UTF-8和UTF-32。)
发布于 2015-05-25 03:59:09
我对php不是很确定,但是在代码点上确实没有调控器。
因此,只有大约110万个有效数据并不重要。
这可能会随时发生变化,但这并不是真正取决于引擎
来执行这一点。有保留的cp是在有效范围内的孔,
有效范围内有代孕,原因不胜枚举
除了字长之外,没有其他限制。
对于UTF- 32,您不能超过31位,因为32是符号位。
0x00000000 - 0x7FFFFFFF
这是有意义的,因为unsigned int
作为一种数据类型是32位硬件寄存器的自然大小。
对于UTF- 16,更准确地说,您可以看到相同的限制被屏蔽到16位。位32仍然是符号位,将0x0000 - 0xFFFF
保留为有效范围。
通常,如果你使用支持ICU的引擎,你应该能够使用它,
它将source和regex都转换为UTF-32。Boost Regex就是这样一个引擎。
编辑:
关于UTF-16
我猜当Unicode超过16位时,他们在16位代理对的范围内打了一个洞。但它只在两个对之间留下了总共20个可用的比特。
每个代理中有10位,其它6位用于确定hi或L0。
看起来这给Unicode人员留下了20位的限制+额外的0xFFFF舍入,总共有0x10FFFF代码点,有不可用的漏洞。
能够将所有码点转换为不同的编码(8/16/32)
实际上必须是可转换的。因此,永远向后兼容的20位是
他们早先遇到的陷阱,但现在必须接受。
无论如何,正则表达式引擎不会在短期内强制实施这一限制,可能永远不会。
就代理而言,它们就是空洞,格式错误的文本代理不能在模式之间转换。这只适用于转换期间的文字编码字符,而不是一个字符的十六进制表示。例如,很容易在UTF-16 (仅限)模式下搜索未配对的代理,甚至是配对的代理。
但我猜正则表达式引擎并不真正关心漏洞或限制,它们只关心主题字符串处于什么模式。不,引擎不会说:
‘嘿,等等,模式是UTF-16我最好把\x{210C1}
转换成\x{D844}\x{DCC1}
__。等等,如果我这样做了,如果它的量化\x{210C1}+
__,开始在它周围注入正则表达式构造怎么办?更糟糕的是,如果它在[\x{210C1}]
__类中呢?不..最好将它限制为\x{FFFF}
__。
我使用了一些非常好用的伪代码代理转换:
Definitions:
====================
10-bits
3FF = 000000 1111111111
Hi Surrogate
D800 = 110110 0000000000
DBFF = 110110 1111111111
Lo Surrogate
DC00 = 110111 0000000000
DFFF = 110111 1111111111
Conversions:
====================
UTF-16 Surrogates to UTF-32
if ( TESTFOR_SURROGATE_PAIR(hi,lo) )
{
u32Out = 0x10000 + ( ((hi & 0x3FF) << 10) | (lo & 0x3FF) );
}
UTF-32 to UTF-16 Surrogates
if ( u32In >= 0x10000)
{
u32In -= 0x10000;
hi = (0xD800 + ((u32In & 0xFFC00) >> 10));
lo = (0xDC00 + (u32In & 0x3FF));
}
Macro's:
====================
#define TESTFOR_SURROGATE_HI(hs) (((hs & 0xFC00)) == 0xD800 )
#define TESTFOR_SURROGATE_LO(ls) (((ls & 0xFC00)) == 0xDC00 )
#define TESTFOR_SURROGATE_PAIR(hs,ls) ( (((hs & 0xFC00)) == 0xD800) && (((ls & 0xFC00)) == 0xDC00) )
//
#define PTR_TESTFOR_SURROGATE_HI(ptr) (((*ptr & 0xFC00)) == 0xD800 )
#define PTR_TESTFOR_SURROGATE_LO(ptr) (((*ptr & 0xFC00)) == 0xDC00 )
#define PTR_TESTFOR_SURROGATE_PAIR(ptr) ( (((*ptr & 0xFC00)) == 0xD800) && (((*(ptr+1) & 0xFC00)) == 0xDC00) )
发布于 2015-05-28 18:27:14
正如minitech在第一条评论中建议的那样,你必须使用代码点-对于这个字符,它是\x{210C1}
。这也是UTF-32中的编码形式。F0 AF AB BF
是UTF8编码的序列(参见http://www.unicode.org/cgi-bin/GetUnihanData.pl?codepoint=210C1)。
在某些版本的PCRE中,您可以使用高达\x{7FFFFFFF}
的值。但我真的不知道有什么可以与之匹配。
引用http://www.pcre.org/pcre.txt
在UTF-16模式下,字符代码为Unicode,范围为0到0x10ffff,但0xd800到0xdfff范围内的值除外,因为这些是成对使用的“代理”值,用于编码大于0xffff的值。..。在UTF-32模式下,字符代码为Unicode,范围为0到0x10ffff,但0xd800到0xdfff范围内的值除外,因为这些值在UTF-32中是格式错误的“代理”值。
0x10ffff
是可用于匹配字符的最大值(这就是我从这里提取的值)。0x10ffff
目前也是unicode标准中定义的最大代码点(参见What are some of the differences between the UTFs?) -因此上面的每个值都没有任何意义(或者我就是不明白)……
https://stackoverflow.com/questions/20954580
复制相似问题