一个关于PHP正则匹配汉字的问题

起因是一个网友提了一个问题:

$pattern='/^\w+$/';
$str="人1994";
$ret = preg_match($pattern, $str, $matches);

他想着\w是应该能够匹配到中文字符“人”的,但是实际执行结果却是不能匹配。网友们给了各种解释和解决方案,总结下来有两个可行方案:

  1. 使用/u模式修饰符[1]
  2. 在pattern中使用unicode编码表示两种方案可以解决如上问题。

代码及输出如下:

<?php


$pattern='/^\w+$/';


$str="人1994";


$ret = preg_match($pattern, $str, $matches);


var_dump($ret);


var_dump($matches);





$pattern='/^\w+$/u';


$str="人1994";


$ret = preg_match($pattern, $str, $matches);


var_dump($ret);


var_dump($matches);





//From PHP 7.0


$pattern='/^\w+$/u';


$str="\u{4eba}1994";//人 =>  \u4eba


$ret = preg_match($pattern, $str, $matches);


var_dump($ret);


var_dump($matches);








Output for hhvm-3.18.5 - 3.22.0, 7.1.0 - 7.2.4


int(0)


array(0) {


}





int(1)


array(1) {


[0]=>


string(7) "人1994"


}





int(1)


array(1) {


[0]=>


string(7) "人1994"


}








Output for 5.6.0 - 5.6.30


int(0)


array(0) {


}





int(1)


array(1) {


[0]=>


string(7) "人1994"


}





int(0)


array(0) {


}





注意:第三个例子中的语法从PHP 7.0开始支持。[2] [3]

还有一个网友提出了一个观点[4]

这个不是 PHP 的锅,而是 PCRE 库的配置导致,\w 的匹配官方文档是这么说的 

A “word” character is any letter or digit or the underscore character, that is, any character which can be part of a Perl “word”. The definition of letters and digits is controlled by PCRE’s character tables, and may vary if locale-specific matching is taking place. For example, in the “fr” (French) locale, some character codes greater than 128 are used for accented letters, and these are matched by \w.

也就是说, PCRE 库的 character tables 配置会影响到\w 的匹配

目前没有验证TA所说的是否正确。

 

目前来看最好的方式就在在写pattern时使用模式修饰符/u。

 

References:

[1]https://secure.php.net/manual/zh/reference.pcre.pattern.modifiers.php

 

[2] PHP 7.0 has introduced the “Unicode codepoint escape” syntax.

https://secure.php.net/manual/en/migration70.new-features.php#migration70.new-features.unicode-codepoint-escape-syntax

 

[3] To support large Unicode ranges (ie: [\x{E000}-\x{FFFD}] or \x{10FFFFF}) you must use the modifier ‘/u’ at the end of your expression.

https://secure.php.net/manual/en/function.preg-match.php#90771

 

[4] https://www.v2ex.com/t/262150

https://stackoverflow.com/questions/1330693/validate-username-as-alphanumeric-with-underscores

 

 

HTTP访问控制(CORS, Cross-Origin Resource Sharing)

简单来说,CORS请求分为简单请求(非术语)和预检请求(Preflight Request)。

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:

使用下列方法之一:

GET

HEAD

POST

Fetch 规范定义了对 CORS 安全的首部字段集合,不得人为设置该集合之外的其他首部字段。该集合为:

Accept

Accept-Language

Content-Language

Content-Type (需要注意额外的限制)

DPR

Downlink

Save-Data

Viewport-Width

Width

Content-Type 的值仅限于下列三者之一:

text/plain

multipart/form-data

application/x-www-form-urlencoded

与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS   方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。”预检请求”的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

 

当请求满足下述任一条件时,即应首先发送预检请求:

使用了下面任一 HTTP 方法:

PUT

DELETE

CONNECT

OPTIONS

TRACE

PATCH

人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:

Accept

Accept-Language

Content-Language

Content-Type (but note the additional requirements below)

DPR

Downlink

Save-Data

Viewport-Width

Width

Content-Type 的值不属于下列之一:

application/x-www-form-urlencoded

multipart/form-data

text/plain

对于预检请求,浏览器会先发送一个预检请求给服务端,服务端正常响应(服务器是否同意客户端继续请求)后才会发送实际请求。

References:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS