aardio 官方社区

 找回密码
 注册会员

QQ登录

只需一步,快速开始

搜索
查看: 141399|回复: 69

模式匹配快速入门

 火... [复制链接]

166

主题

2154

回帖

1万

积分

管理员

积分
13056
发表于 2010-11-29 16:27:13 | 显示全部楼层 |阅读模式
此教程在 aardio 文档里有另一个版本:《  aardio 模式匹配快速入门 》 主要是排版有些区别,文档修订与更新的优先级更高,论坛帖子一些小的问题不再处理。。

一个最简单的模式匹配代码:
var 结果 = string.match("字符串","这里是模式串")

模式串有两个基本的元素:

1. 子模式 - 指定匹配的数据
2. 运算符 - 指定匹配的规则

一、子模式


子模式是模式串里的最小匹配单位,用于表示字符或某一类的字符(或连续的字符序列)。

1. 字面值

字面值指的是a表示a, b表示b,字面意思是什么就表示什么,这个不难理解。
var 匹配结果 = string.match("abcd","abc")   

2. 任意字符

一个小圆点"."表示任意单字节字符( 与正则表达式类似 )。
而一个冒号":"表示任意多字节字符( 例如中文字符,正则表达式都是用单个点表示 ) 。

3. 预定义的字符类

正则表达式兼容的字符类:

\n 换行符
\r 回车符
\w 字母和数字
\s 空白符
\d 数字
\f 换页符 '\x0c'
\v 匹配一个垂直制表符。等价于 '\x0b'
\t 制表符

其他字符类:


\a 字母
\c 控制字符
\i 是否ASCII字符( 字节码 < 0x80 )
\l 小写字母
\p 标点字符
\u 大写字母
\x 十六进制数字(正则表达式里用于16进制字符前缀,即\xhh)
\z 表示 '\0'

没有任何必要去死记硬背上面的列表

大写表示反义( 与正则表达式相同 ),例如\D表示不是数字的字符。

import console;

var 匹配结果 = string.match("12345678","\d")  
console.log( 匹配结果 ) //显示 1

console.pause();

4. 自定义的字符类

例如`[abcd]`表示字符是 abcd 其中一个,或者`[a-z]`表示 a 到 z 的任意小写字母字符。  

//还是返回 1
var str = string.match("12345678","[1230-9]")   

5. 自定义的字符元序列
例如<a-zabcd> 他的语法与字符一样,但是他表示的是一连的字符序列,而不是其中一个字符。

// 显示 1234
var str = string.match("12345678","<1230-9>")   

元序列可组合多个子模式并将其转换为一个新的子模式(可对其应用其他模式运算符),并且在内部可以支持大多数其他模式语法(不能在元序列内创建捕获组,但可以嵌套包含其他元序列)。元序列是具有原子性的非捕获分组,在内部执行贪婪与激进的匹配规则,只要能匹配到内容就会尽力向后走,并且不会在元序列内执行回溯匹配。

参考文档:元序列


二、运算符


运算符是指定一个模式应当怎样去匹配的特殊符号。

运算符只能用于子模式。

如果将『子模式』理解为编程语言里的操作数,那么『运算符』就相当于编程语言里的操作符。

运算符有很多种,而最常用的就是用来指定匹配次数的量词:

p{2,3} 表示子模式 p 出现 2 到 3 次

//匹配结果为 12345
var str = string.match("12345678","\d{2,5}")

p+  表示子模式 p 出现 1 次到任意次数,等价于 p{1,}

//匹配结果为 12345678
var str = string.match("12345678","\d+")

p* 表示子模式 p 出现 0 次到任意次数,等价于 p{0,}

var str = string.match("12345678","\d+\s*") //这里的"\s*"匹配零个或多个空格   


166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2010-11-29 16:27:30 | 显示全部楼层

模式匹配应用实例

模式匹配对正则表达式进行了简化,保留基本语法,牺牲一些功能换取效率。

一、最简单的模式串

例如模式串 "\d+"  包含两个部分:

  • "\d" 表示数字。这里的`\d`还可以换成`[0-9]` ,它们的意思是一样的。`[0-9]` 等价于 `[0123456789]`。 **中括号表示自定义的一个字符集合,只要目标字符是其中的一个就匹配成功。**
  • 运算符  "+" 示匹配一次或多次,这个也可以写为"{1,}" 意思是一样的。


二、模式匹配身份证号码


我们看一个身份证匹配的模式串 "\d{15,18}"  ,用于指匹配15到18个数值

1. 自定义字符集合

但我们遇到的一个问题是,最后一位可能不是数值,也有一种可能是x。
那么我们就要改为"\d{14,17}[\dx]"
但是别人还有可能把x大写啊,所以继续修改为:
"\d{14,17}[\dxX]"
2. 元序列

身份证还不能是 16 位, 17 位数字。所以我们继续修改为:
var 结果 = string.match("身份证号码","\d{14,14}<\d\d\d>*[\dxX]" )
像这些,多动手折腾很快会明白,别人灌输给你的知识永远没有自已探索到的理解深刻。

3. 首尾锚点

更进一步,19 位,20 位的数值都可能匹配成功,因为他只要匹配其中18位就成功了,这时候我们还要限定他前面后面都不能有其他的字符,这时就要指定首尾锚点,用 `^` 表示文本开始位置的锚点,用 `$` 表示文本结束位置的锚点。

例如:
var str = string.match("身份证号码","^\d{14,14}<\d\d\d>*[\dxX]$" )

4. 跳过空白字符

但是这样还有一个问题,如果身份证号码前后可能有空格怎么办呢?  
可以用 `\s` 表示所有空白字符,加上匹配零到多次的量词运算符就是"\s*",再改进如下:
var str = string.match("身份证号码","^\s*\d{14,14}<\d\d\d>*[\dxX]\s*$" )  

5. 边界断言

如果身份证前后不仅仅是空格,还可能有别的字符,哪怎么办呢?

这里我们可以接触一个新的概念:边界
边界是在子模式前面加一个表示否定的感叹号,表示从不匹配(左侧)到匹配(右侧)的边界,例如
"!\d" 表示不是数字到数字交界的位置,这是一个试探性的零宽匹配,匹配的仅仅是边界,消耗的字符串长度为 0。

加上边界断言后的代码如下:
import console;
var idNumber = "sfz612323198608110000fgd"  
idNumber = string.match(idNumber,
"!\d(\d{14}<\d\d\d>*[\dxX])![^\dxX]")  

console.log(idNumber);
console.pause(
true);

这些需要在实践中嗑碰出来的知识,如流水无形,无一定之规

166

主题

2154

回帖

1万

积分

管理员

积分
13056
 楼主| 发表于 2010-11-29 16:27:37 | 显示全部楼层

模式匹配中的那些括号

可以熟练使用模式匹配中的括号,表示你精通了模式匹配。
[ab] 中括号匹配指定字符中的一个,这被称为自定义字符集合

p{2,3} 大括号指定模式重复匹配的次数,这是一个量词运算符

<ab> 尖括号用于创建创建元序列(非捕获分组),可用于匹配一连串的字符序列
(p)
  圆括号用于创建捕获分组,用于捕获模式匹配匹配的子串。每增加一对圆括号,匹配函数就多一个返回值

《模式匹配语法参考》
http://www.aardio.com/zh-cn/doc/library-guide/builtin/string/patterns.html

《模式匹配函数说明》
http://www.aardio.com/zh-cn/doc/library-guide/builtin/string/matching.html

多结合实际案例练习,多到论坛跟大家交流。
然后你也尝试象我这样写教程,不要怕写的不好。
把自已的学习心得写出来。

4

主题

94

回帖

558

积分

荣誉会员

积分
558
发表于 2010-11-29 23:12:32 | 显示全部楼层
太好了,这个一定得学,先收藏

3

主题

47

回帖

545

积分

荣誉会员

积分
545
发表于 2010-11-29 23:48:05 | 显示全部楼层
真不错,写得很明白。

40

主题

519

回帖

3015

积分

新手入门

超级初学者

积分
3015
发表于 2010-11-30 00:04:44 | 显示全部楼层
  1. string.match("身份证号码","^\s*\d{14,14}<\d\d\d>*[\dxX]\s*$" )
复制代码
不能排除14位数字+x可以理解,需要加判断条件。
不能排除17位数字,看不明白为什么

117

主题

1103

回帖

6572

积分

六级会员

积分
6572
发表于 2010-11-30 10:01:29 | 显示全部楼层
回复 fantasynew 的帖子

^\s*\d{14,14}<\d\d\d>*[\dxX]\s*$
^起
\s空白
\s*0或者0以上的空白
\d数字
\d{14,14}连续14个数字
<\d\d\d>连续3个数字,放在<>内将他看作一个整体
<\d\d\d>*表示<>的3个数字可有可无,存在的时候必须是3的个一起出现
[\dxX]数字和x以及X内三个随便出现一个
$止
这个 表达式 除了能匹配出15,18位的 还能匹配出21,24 等
比赛的6楼  已经成功解决此问题

6

主题

157

回帖

897

积分

荣誉会员

爱生活,爱拉芳。

积分
897
发表于 2010-11-30 14:57:52 | 显示全部楼层
这就是俺想看的教程。老大辛苦。一定要细细读,这个教程中提到的知识点,绝不能当问题再提出

56

主题

412

回帖

3788

积分

荣誉会员

积分
3788
发表于 2010-11-30 15:57:05 | 显示全部楼层
继续加深匹配知识

1

主题

22

回帖

136

积分

培训班

积分
136
发表于 2010-11-30 15:57:17 | 显示全部楼层
本帖最后由 jihuxi 于 2010-11-30 16:00 编辑

细细的看了一遍。
但是:
import console;//打开控制台
sfz="dsf612323198608110000fgd"
结果 = string.match(sfz,"!\d(\d{14}<\d\d\d>*[\dxX])![\dxX]")
console.log( 结果 )
console.pause()

结果是null  

点评

晕,不是,这样改就少了一个数字了!!  发表于 2010-11-30 16:28
![\dxX] 改成 [!\dxX]  发表于 2010-11-30 16:27

1

主题

22

回帖

136

积分

培训班

积分
136
发表于 2010-11-30 17:44:45 | 显示全部楼层
谢谢 cbtan

56

主题

412

回帖

3788

积分

荣誉会员

积分
3788
发表于 2010-11-30 17:49:11 | 显示全部楼层
回复 jihuxi 的帖子

,,我说的是错的!

1

主题

22

回帖

136

积分

培训班

积分
136
发表于 2010-11-30 18:07:24 | 显示全部楼层
啊,我把 ![\dxX] 改成 [!\dxX]   运行结果为:612323198608110000

14

主题

51

回帖

386

积分

荣誉会员

积分
386
发表于 2010-12-24 00:41:18 | 显示全部楼层
看了一半,明天再看。

6

主题

57

回帖

387

积分

荣誉会员

积分
387
发表于 2010-12-24 10:25:46 | 显示全部楼层
收藏,收藏,再收藏

39

主题

163

回帖

1351

积分

四级会员

积分
1351
发表于 2010-12-24 11:09:15 | 显示全部楼层
大力支持楼主的伟大贡献!

3

主题

21

回帖

135

积分

一级会员

积分
135
发表于 2010-12-25 14:44:59 | 显示全部楼层
看着怎么像是正则表达式了,是一个意思不?

3

主题

21

回帖

135

积分

一级会员

积分
135
发表于 2010-12-25 14:49:56 | 显示全部楼层
原来如此。明白了

0

主题

1

回帖

13

积分

新手入门

积分
13
发表于 2011-1-12 13:04:40 | 显示全部楼层
还是新手,完全是陌生的东西,好深奥,要学习啊
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

手机版|未经许可严禁引用或转载本站文章|aardio.com|aardio 官方社区 ( 皖ICP备09012014号 )

GMT+8, 2025-1-13 13:41 , Processed in 0.077446 second(s), 31 queries .

Powered by Discuz! X3.5

Copyright © 2001-2024 Tencent Cloud.

快速回复 返回顶部 返回列表