大家好,我是老码农,今天咱们来聊聊 JavaScript 正则表达式中的一个“V”字仇杀队的“V”—— v
flag,也叫 Unicode Property Escapes。这玩意儿听起来高大上,但其实是个帮你更好地处理 Unicode 字符的小助手。
开场白:Unicode 的那些事儿
在说v
flag 之前,咱们得先简单回顾一下 Unicode。早些年,ASCII 那128个字符还能勉强应付一下英语,但随着互联网全球化,各种语言都冒出来了,ASCII 就歇菜了。Unicode 就是来拯救世界的,它给每个字符都分配了一个唯一的数字,也就是码点(code point)。
但是,Unicode 字符集实在太大了,什么奇奇怪怪的符号都有。光靠 w
、d
、s
这些简化的字符类,你根本没法精确匹配。比如,你想匹配所有的中文字符,用 w
肯定不行,因为它还会包含英文、数字和下划线。
进入正题:v
flag 的闪亮登场
这个时候,v
flag 就派上用场了。它允许你在正则表达式中使用 Unicode Property Escapes,也就是用 p{}
和 P{}
这样的语法来匹配具有特定 Unicode 属性的字符。
p{...}
:匹配具有指定属性的字符。P{...}
:匹配不具有指定属性的字符。
这俩货就像是正则表达式里的魔法咒语,能让你轻松驾驭 Unicode 字符。
v
flag 的语法和用法
要使用 v
flag,你需要在正则表达式的末尾加上 v
。例如:
const regex = /p{Script=Han}+/v; // 匹配一个或多个汉字
const str = "你好世界!";
console.log(regex.test(str)); // 输出: true
注意,v
flag 必须和 u
flag 共存。这是因为 Unicode Property Escapes 本身就是 Unicode 特性,没有 u
flag,JavaScript 就不会把正则表达式中的字符当成 Unicode 码点来处理。
Unicode Property Escapes 的种类
Unicode Property Escapes 分为两大类:
- General Category Properties(通用类别属性):描述字符的一般类型,比如字母、数字、标点符号等等。
- Script Properties(脚本属性):描述字符所属的文字系统,比如汉字、希腊字母、西里尔字母等等。
1. General Category Properties
General Category Properties 用两个字母的代码表示,例如:
Lu
:大写字母(Uppercase letter)Ll
:小写字母(Lowercase letter)Lt
:词首字母大写的字母(Titlecase letter)Lm
:修饰字母(Modifier letter)Lo
:其他字母(Other letter)Mn
:非间距标记(Nonspacing mark)Mc
:间距组合标记(Spacing combining mark)Me
:封闭标记(Enclosing mark)Nd
:十进制数字(Decimal number)Nl
:字母数字(Letter number)No
:其他数字(Other number)Ps
:左括号(Punctuation, open)Pe
:右括号(Punctuation, close)Pi
:起始引号(Punctuation, initial quote)Pf
:结束引号(Punctuation, final quote)Pc
:连接标点符号(Punctuation, connector)Pd
:破折号(Punctuation, dash)Po
:其他标点符号(Punctuation, other)Sm
:数学符号(Symbol, math)Sc
:货币符号(Symbol, currency)Sk
:修饰符号(Symbol, modifier)So
:其他符号(Symbol, other)Zs
:空格分隔符(Separator, space)Zl
:行分隔符(Separator, line)Zp
:段落分隔符(Separator, paragraph)Cc
:控制字符(Other, control)Cf
:格式字符(Other, format)Cs
:代理对(Other, surrogate)Co
:私用字符(Other, private use)Cn
:未分配字符(Other, not assigned)
你可以用 p{General_Category=...}
或者简写形式 p{...}
来使用这些属性。
例如,匹配一个大写字母:
const regex = /p{Lu}/vu; // 注意 vu 的顺序无所谓
console.log(regex.test("A")); // 输出: true
console.log(regex.test("a")); // 输出: false
匹配一个数字:
const regex = /p{Nd}/vu;
console.log(regex.test("1")); // 输出: true
console.log(regex.test("a")); // 输出: false
2. Script Properties
Script Properties 用脚本名称表示,例如:
Han
:汉字Latin
:拉丁字母Greek
:希腊字母Cyrillic
:西里尔字母Arabic
:阿拉伯字母Hebrew
:希伯来字母Devanagari
:梵文
你可以用 p{Script=...}
来使用这些属性。
例如,匹配一个汉字:
const regex = /p{Script=Han}/vu;
console.log(regex.test("你")); // 输出: true
console.log(regex.test("a")); // 输出: false
匹配一个希腊字母:
const regex = /p{Script=Greek}/vu;
console.log(regex.test("α")); // 输出: true
console.log(regex.test("a")); // 输出: false
实战演练:用 v
flag 解决实际问题
光说不练假把式,咱们来几个实际的例子。
例子 1:提取字符串中的所有汉字
function extractChinese(str) {
const regex = /p{Script=Han}/gvu;
const result = str.match(regex);
return result ? result.join('') : '';
}
const str = "Hello 你好 世界!123";
console.log(extractChinese(str)); // 输出: 你好世界
例子 2:验证用户输入的用户名是否只包含字母、数字和下划线,并且允许中文
function isValidUsername(username) {
const regex = /^[wp{Script=Han}]+$/vu;
return regex.test(username);
}
console.log(isValidUsername("老码农123")); // 输出: true
console.log(isValidUsername("old_coder")); // 输出: true
console.log(isValidUsername("old-coder")); // 输出: false
例子 3:计算字符串中汉字的个数
function countChineseCharacters(str) {
const regex = /p{Script=Han}/gvu;
const matches = str.matchAll(regex);
let count = 0;
for (const match of matches) {
count++;
}
return count;
}
const str = "你好世界,Hello World!";
console.log(countChineseCharacters(str)); // 输出 4
v
flag 的进阶用法
除了直接使用 General Category Properties 和 Script Properties,v
flag 还支持一些更高级的用法。
- Boolean Math (布尔运算)
你可以使用 &
(与)、|
(或)、~
(非)来组合不同的属性。
例如,匹配既是字母又是大写的字符:
const regex = /p{Lu & Letter}/vu; // Letter是Lu, Ll, Lt, Lm, Lo的简称
console.log(regex.test("A")); // 输出: true
console.log(regex.test("a")); // 输出: false
console.log(regex.test("1")); // 输出: false
匹配不是数字的字符:
const regex = /p{~Nd}/vu;
console.log(regex.test("a")); // 输出: true
console.log(regex.test("1")); // 输出: false
- Binary Properties (二元属性)
有些属性只有两种状态:true 或 false。例如:
Uppercase
:是否为大写字母Lowercase
:是否为小写字母Alphabetic
:是否为字母Ideographic
:是否为表意文字(例如汉字)Emoji
:是否为表情符号
你可以直接使用这些属性,例如:
const regex = /p{Uppercase}/vu;
console.log(regex.test("A")); // 输出: true
console.log(regex.test("a")); // 输出: false
匹配一个表情符号:
const regex = /p{Emoji}/vu;
console.log(regex.test("😀")); // 输出: true
console.log(regex.test("a")); // 输出: false
- Unicode Block (Unicode 块)
Unicode 把字符集划分成一个个的块(block),你可以用 p{Block=...}
来匹配特定块中的字符。例如:
Basic_Latin
:基本拉丁字母CJK_Unified_Ideographs
:CJK 统一表意符号(汉字)Greek_and_Coptic
:希腊字母和科普特字母
例如,匹配一个基本拉丁字母:
const regex = /p{Block=Basic_Latin}/vu;
console.log(regex.test("a")); // 输出: true
console.log(regex.test("你")); // 输出: false
一些需要注意的点
- 性能问题:虽然
v
flag 很强大,但它可能会降低正则表达式的性能,尤其是在处理大量文本时。所以,在性能敏感的场景下,要谨慎使用。 - 浏览器兼容性:
v
flag 的兼容性还可以,主流浏览器都支持。但是,为了兼容老版本的浏览器,你可能需要使用 Babel 等工具进行转译。 - 属性名称大小写:Unicode Property Escapes 的属性名称是区分大小写的。例如,
p{Script=Han}
和p{script=han}
是不同的。但是为了健壮性, 推荐按照规范来写. - 短横线和下划线:在属性名称中,短横线
-
和下划线_
是等价的。例如,p{General_Category=Lowercase_Letter}
和p{General-Category=Lowercase-Letter}
是一样的。
总结:v
flag 的价值
v
flag 就像是正则表达式的瑞士军刀,让你在处理 Unicode 字符时更加得心应手。它可以帮助你:
- 更精确地匹配特定类型的字符。
- 轻松处理各种语言的文本。
- 编写更健壮、更易于维护的正则表达式。
表格总结:v
flag 常用属性
属性类型 | 属性名称 | 描述 | 示例 |
---|---|---|---|
General Category | Lu |
大写字母 | /p{Lu}/vu.test("A") // true |
General Category | Ll |
小写字母 | /p{Ll}/vu.test("a") // true |
General Category | Nd |
十进制数字 | /p{Nd}/vu.test("1") // true |
Script | Han |
汉字 | /p{Script=Han}/vu.test("你") // true |
Script | Latin |
拉丁字母 | /p{Script=Latin}/vu.test("a") // true |
Binary | Uppercase |
是否为大写字母 | /p{Uppercase}/vu.test("A") // true |
Binary | Lowercase |
是否为小写字母 | /p{Lowercase}/vu.test("a") // true |
Binary | Emoji |
是否为表情符号 | /p{Emoji}/vu.test("😀") // true |
Block | Basic_Latin |
基本拉丁字母块 | /p{Block=Basic_Latin}/vu.test("a") // true |
Boolean Math | p{Lu & Alphabetic} |
既是大写字母又是字母 | /p{Lu & Alphabetic}/vu.test("A") // true |
Negation | p{~Nd} |
不是数字的字符 | /p{~Nd}/vu.test("a") // true |
结束语:拥抱 Unicode,拥抱 v
flag
Unicode 已经成为互联网世界的基石,掌握 Unicode Property Escapes 是每个 JavaScript 开发者必备的技能。v
flag 就像一把钥匙,打开了 Unicode 的宝藏,让你在处理文本时更加游刃有余。希望今天的讲座能帮助你更好地理解和使用 v
flag,在你的编程之路上更上一层楼!
好了,今天的分享就到这里,感谢大家的观看,我们下次再见!