问题
用正则表达式匹配微博中@用户昵称。
*如果您想直接看答案,选中这里->答案:/^[x{4e00}-x{9fa5}]/u
微博里的用户昵称规则是中文、英文、数字,减号和下划线。
前端JS的验证规则是new RegExp(“^[0-9a-zA-Zu4e00-u9fa5_-]*$”).test();
第一个方案
1 | '/@([0-9a-zA-Zu4e00-u9fa5_-]*)/' |
运行了一下,出错了:
1 | Warning: preg_match(): Compilation failed: PCRE does not support L, l, N, P, p, U, u, or X at offset |
在网上搜了一下:
PHP正则表达式中不支持下列 Perl 转义序列:L, l, N, P, p, U, u, or X
在 UTF-8 模式下,允许用“x{…}”,花括号中的内容是表示十六进制数字的字符串。原来的十六进制转义序列 xhh 如果其值大于 127 的话则匹配了一个双字节 UTF-8 字符。
第二个解决方案
1 | "/^[x80-xff_a-zA-Z0-9]{3,15}$" |
这个貌似只能匹配全角字符,错误提示没了,但是匹配的不全,还出乱码。
第三个解决方案
- GB2312汉字字母数字下划线正则表达式
1 | preg_match("/^[".chr(0xa1)."-".chr(0xff)."A-Za-z0-9_]+$/",$str)) |
- UTF-8汉字字母数字下划线正则表达式
1 | preg_match("/^[x{4e00}-x{9fa5}A-Za-z0-9_]+$/u",$str)) |
这个看似很靠谱但是还是报错了:
1 | Compilation failed: character value in x{...} sequence is too large |
最后用这个错误信息搜到了eqida的技术日志上的解决方案
第四个解决方案
1 | preg_match("/^[x{4e00}-x{9fa5}]{1,4}/u",$str); |
加入参数u,错误消失,匹配正确。
一般来说,指定代码点的形式有3种:『uxxxx』、『u{xxxx}』、『x{xxxx}』(其中的xxxx为编码的值,u之后必须有4位 16进制数字)。.NET、Java、JavaScript和Python使用第一种方式,而PHP和Ruby使用第二种方式(Ruby 1.9以上版本才支持这种表示法),PHP使用第三种方式。
而且PHP必须指定Unicode模式。