irc*_*ell 19 php regex validation utf-8
在PHP中,我们可以mb_check_encoding()
用来确定字符串是否是有效的UTF-8.但这不是一个可移植的解决方案,因为它需要编译和启用mbstring扩展.此外,它不会告诉我们哪个字符无效.
是否有正则表达式(或其他100%可移植方法)可以匹配给定字符串中的无效UTF-8字节.这样,如果需要,可以替换这些字节(保留二进制信息,例如在构建包含二进制数据的测试输出xml文件时).因此,将字符转换为UTF-8将丢失信息.所以,我们可能想转换:
"foo" . chr(128) . chr(255)
Run Code Online (Sandbox Code Playgroud)
成
"foo<128><255>"
Run Code Online (Sandbox Code Playgroud)
所以只是"检测"字符串不够好,我们需要能够检测哪些字符无效.
irc*_*ell 36
您可以使用此PCRE正则表达式检查字符串中的有效UTF8.如果正则表达式匹配,则该字符串包含无效的字节序列.它是100%可移植的,因为它不依赖于PCRE_UTF8来编译.
$regex = '/(
[\xC0-\xC1] # Invalid UTF-8 Bytes
| [\xF5-\xFF] # Invalid UTF-8 Bytes
| \xE0[\x80-\x9F] # Overlong encoding of prior code point
| \xF0[\x80-\x8F] # Overlong encoding of prior code point
| [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
| [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
| [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
| (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
| (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
| (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
| (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
| (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
)/x';
Run Code Online (Sandbox Code Playgroud)
我们可以通过创建一些文本变体来测试它.
// Overlong encoding of code point 0
$text = chr(0xC0) . chr(0x80);
var_dump(preg_match($regex, $text)); // int(1)
// Overlong encoding of 5 byte encoding
$text = chr(0xF8) . chr(0x80) . chr(0x80) . chr(0x80) . chr(0x80);
var_dump(preg_match($regex, $text)); // int(1)
// Overlong encoding of 6 byte encoding
$text = chr(0xFC) . chr(0x80) . chr(0x80) . chr(0x80) . chr(0x80) . chr(0x80);
var_dump(preg_match($regex, $text)); // int(1)
// High code-point without trailing characters
$text = chr(0xD0) . chr(0x01);
var_dump(preg_match($regex, $text)); // int(1)
Run Code Online (Sandbox Code Playgroud)
等等...
实际上,由于这与无效字节匹配,因此您可以在preg_replace中使用它来替换它们:
preg_replace($regex, '', $text); // Remove all invalid UTF-8 code-points
Run Code Online (Sandbox Code Playgroud)
hak*_*kre 10
我把它放在这里是为了完整:
假设PHP是使用PCRE编译的,它通常也使用UTF-8启用.因此,在问题中明确要求这个非常简单的正则表达式可以检测到无效的UTF-8字符串,因为它们不匹配:
preg_match('//u', $string);
Run Code Online (Sandbox Code Playgroud)
然后你可以论证u
修饰符(PCRE_UTF8)并不总是可用,并且为真,这可能发生在这个问题显示:
然而,在我的实际开发人员现场,这从来都不是问题.更有一个问题是PCRE扩展根本不可用,这会导致包含pcre的任何答案都无用(甚至我的这里).但大多数情况下,这个问题更像是过去的问题,而不是今天的问题.
在某种程度上重复的问题给出了一个类似于这个问题的更长的答案:
所以我认为这个问题应该突出建议答案附带的更多好处.
W3C 有一个页面(标题为“多语言表单编码”),其中列出了以下与有效 UTF-8 字符串相匹配的Perl 正则表达式。
(请注意,这与此 SO 问题的另一个答案中列出的正则表达式相反,该正则表达式匹配无效的UTF-8 字符串。)
# Returns true if $field is UTF-8, and false otherwise.
$field =~
m/\A(
[\x00-\x7F] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*\z/x;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
12958 次 |
最近记录: |