正则表达式(Regular Expressions)
正则表达式(Regular Expressions) 正则表达式在其他编程语言中的应用非常广泛,网上资料也非常多,而网上在ABAP语言中应用的资料却很少,尽管各语言中正则表达式语法知识都很类似,但仍然有一些区别,本文主要是简单介绍一下其基本语法。总结一下,方便大家查阅。 欢迎转载,请注明出处,文中不足之处还望指正。(Email:hubin0809@126.com) 一、简要认识 正则表达式就是用一个“字符串”来描述一个特征,然后去验证另一个“字符串”是否符合这个特征。比如表达式“ab+” 描述的特征是“一个 'a' 和任意个 'b' ”,那么 'ab','abb','abbbbbbbbbb' 都符合这个特征。 正则表达式可以用来:(1)验证字符串是否符合指定特征,比如验证是否是合法的邮件地址。(2)用来查找字符串,从一个长的文本中查找符合指定特征的字符串,比查找固定字符串更加灵活方便。(3)用来替换,比普通的替换更强大。 举例
解释: 1> 'w+@w+(.w+)+'中 w 是表示任意一个字母或数字或下划线,+ 表示前面字符个数为一个或多个,@即为’@’字符 2> matcher参照类cl_abap_matcher,match有匹配的意思,调用静态方法create创建了匹配的对(暂时这么理解,好吧,我承认我不知道怎么形容),然后调用match方法,返回值中’X’表示匹配,SPACE表示不匹配。 具体含义后面会讲到,本程序主要是验证邮件地址是否合法。
二、语法规则
pattern模板,text要匹配的字符,match匹配结果,’X’表示匹配,SPACE表示不匹配。 1、普通字符 字母、数字、汉字、下划线、以及后面没有特殊定义的标点符号,都是"普通字符"。表达式中的普通字符,在匹配一个字符串的时候,匹配与之相同的一个字符。
2、转义字符 一些不便书写的字符,采用在前面加 "" 的方法。例如’.’
7、其他一些代表抽象意义的特殊符号
^ |
与字符串开始的地方匹配,不匹配任何字符 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$ |
与字符串结束的地方匹配,不匹配任何字符 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
b |
匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |
左右两边表达式之间 "或" 关系,匹配左边或者右边 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
( ) |
(1). 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
(?: ) |
匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 |
进一步的文字说明仍然比较抽象,因此,举例帮助大家理解。
举例1:表达式 "^aaa" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "^" 要求与字符串开始的地方匹配,因此,只有当 "aaa" 位于字符串的开头的时候,"^aaa" 才能匹配,比如:"aaa xxx xxx"。
举例2:表达式 "aaa$" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "$" 要求与字符串结束的地方匹配,因此,只有当 "aaa" 位于字符串的结尾的时候,"aaa$" 才能匹配,比如:"xxx xxx aaa"。
举例3:表达式 ".b." 在匹配 "@@@abc" 时,能够找到匹配的内容;匹配到的内容是:"@a";匹配到的位置是:开始于2,结束于4。
进一步说明:"b" 与 "^" 和 "$" 类似,本身不匹配任何字符,但是它要求它在匹配结果中所处位置的左右两边,其中一边是 "w" 范围,另一边是 非"w" 的范围。
举例4:表达式 "bendb" 在匹配 "weekend,endfor,end" 时,能够找到匹配的内容;匹配到的内容是:"end";匹配到的位置是:开始于15,结束于18。
Pattern |
Match |
||||||||
(.{1,3})|(.{5,}) |
bcade |
三、正则表达式中的一些高级规则(ABAP部分支持)
1、 匹配次数中的贪婪与非贪婪贪婪模式: 在使用修饰匹配次数的特殊符号时,有几种表示方法可以使同一个表达式能够匹配不同的次数,比如:"{m,n}","{m,}","?","*","+",具体匹配的次数随被匹配的字符串而定。这种重复匹配不定次数的表达式在匹配过程中,总是尽可能多的匹配。比如,针对文本 "dxxxdxxxd",举例如下:
由此可见,"w+" 在匹配的时候,总是尽可能多的匹配符合它规则的字符。虽然第二个举例中,它没有匹配最后一个 "d",但那也是为了让整个表达式能够匹配成功。同理,带 "*" 和 "{m,n}" 的表达式都是尽可能地多匹配,带 "?" 的表达式在可匹配可不匹配的时候,也是尽可能的 "要匹配"。这种匹配原则就叫作 "贪婪" 模式 。 非贪婪模式:(ABAP暂时不支持,但是最好理解吧) (d)(w+?) |
"w+?" 将尽可能少的匹配第一个 "d" 之后的字符,结果是:"w+?" 只匹配了一个 "x" |
||||||
(d)(w+?)(d) |
为了让整个表达式匹配成功,"w+?" 不得不匹配 "xxx" 才可以让后边的 "d" 匹配,从而使整个表达式匹配成功。因此,结果是:"w+?" 匹配 "xxx" |
更多的情况,举例如下:
举例1:表达式 "<td>(.*)</td>" 与字符串 "<td><p>aa</p></td> <td><p>bb</p></td>" 匹配时,匹配的结果是:成功;匹配到的内容是 "<td><p>aa</p></td> <td><p>bb</p></td>" 整个字符串, 表达式中的 "</td>" 将与字符串中最后一个 "</td>" 匹配。
举例2:相比之下,表达式 "<td>(.*?)</td>" 匹配举例1中同样的字符串时,将只得到 "<td><p>aa</p></td>", 再次匹配下一个时,可以得到第二个 "<td><p>bb</p></td>"。
2、 反向引用 1,2
表达式在匹配时,表达式引擎会将小括号 "( )" 包含的表达式所匹配到的字符串记录下来。在获取匹配结果的时候,小括号包含的表达式所匹配到的字符串可以单独获取。这一点,在前面的举例中,已经多次展示了。在实际应用场合中,当用某种边界来查找,而所要获取的内容又不包含边界时,必须使用小括号来指定所要的范围。比如前面的 "<td>(.*?)</td>"。
其实,"小括号包含的表达式所匹配到的字符串" 不仅是在匹配结束后才可以使用,在匹配过程中也可以使用。表达式后边的部分,可以引用前面 "括号内的子匹配已经匹配到的字符串"。引用方法是 "" 加上一个数字。"1" 引用第1对括号内匹配到的字符串,"2" 引用第2对括号内匹配到的字符串……以此类推,如果一对括号内包含另一对括号,则外层的括号先排序号。换句话说,哪一对的左括号 "(" 在前,那这一对就先排序号。
举例如下:
举例1:表达式 "('|")(.*?)1" 在匹配 " 'Hello',"World" " 时,匹配结果是:成功;匹配到的内容是:" 'Hello' "。再次匹配下一个时,可以匹配到 " "World" "。
举例2:表达式 "(w)1{4,}" 在匹配 "aa bbbb abcdefg ccccc 111121111 999999999" 时,匹配结果是:成功;匹配到的内容是 "ccccc"。再次匹配下一个时,将得到 999999999。这个表达式要求 "w" 范围的字符至少重复5次,注意与 "w{5,}" 之间的区别。
举例3:表达式 "<(w+)s*(w+(=('|").*?4)?s*)*>.*?</1>" 在匹配 "<td id='td1' style="bgcolor:white"></td>" 时,匹配结果是成功。如果 "<td>" 与 "</td>" 不配对,则会匹配失败;如果改成其他配对,也可以匹配成功。
3、 预搜索
前面的章节中,我讲到了几个代表抽象意义的特殊符号:"^","$","b"。它们都有一个共同点,那就是:它们本身不匹配任何字符,只是对 "字符串的两头" 或者 "字符之间的缝隙" 附加了一个条件。理解到这个概念以后,本节将继续介绍另外一种对 "两头" 或者 "缝隙" 附加条件的,更加灵活的表示方法。
正向预搜索:"(?=xxxxx)","(?!xxxxx)"
格式:"(?=xxxxx)",在被匹配的字符串中,它对所处的 "缝隙" 或者 "两头" 附加的条件是:所在缝隙的右侧,必须能够匹配上 xxxxx 这部分的表达式。因为它只是在此作为这个缝隙上附加的条件,所以它并不影响后边的表达式去真正匹配这个缝隙之后的字符。这就类似 "b",本身不匹配任何字符。"b" 只是将所在缝隙之前、之后的字符取来进行了一下判断,不会影响后边的表达式来真正的匹配。
举例1:表达式 "Windows (?=NT|XP)" 在匹配 "Windows 98,Windows NT,Windows 2000" 时,将只匹配 "Windows NT" 中的 "Windows ",其他的 "Windows " 字样则不被匹配。
举例2:表达式 "(w)((?=111)(1))+" 在匹配字符串 "aaa ffffff 999999999" 时,将可以匹配6个"f"的前4个,可以匹配9个"9"的前7个。这个表达式可以读解成:重复4次以上的字母数字,则匹配其剩下最后2位之前的部分。当然,这个表达式可以不这样写,在此的目的是作为演示之用。
格式:"(?!xxxxx)",所在缝隙的右侧,必须不能匹配 xxxxx 这部分表达式。
举例3:表达式 "((?!bstopb).)+" 在匹配 "fdjka ljfdl stop fjdsla fdj" 时,将从头一直匹配到 "stop" 之前的位置,如果字符串中没有 "stop",则匹配整个字符串。
举例4:表达式 "do(?!w)" 在匹配字符串 "done,do,dog" 时,只能匹配 "do"。在本条举例中,"do" 后边使用 "(?!w)" 和使用 "b" 效果是一样的。
表达式 |
方向 |
说明 |
(?=xxx) |
正向预搜索(向右) |
正向预搜索,判断当前位置右侧是否能匹配指定表达式 |
(?!xxx) |
正向预搜索否定,判断当前位置右侧是否不能够匹配指定表达式 |
|
(?<=xxx) |
反向预搜索(向左)[ABAP不支持] |
反向预搜索,判断当前位置左侧是否能够匹配指定表达式 |
(?<!xxx) |
反向预搜索否定,判断当前位置左侧是否不能够匹配指定表达式 |
4、 其他补充
1> 在表达式 "s","d","w","b" 表示特殊意义的同时,其大写字母表示相反的意义
可匹配 |
|
S |
匹配所有非空白字符("s" 可匹配各个空白字符) |
D |
匹配所有的非数字字符 |
W |
匹配所有的字母、数字、下划线以外的字符 |
B |
匹配非单词边界,即左右两边都是 "w" 范围或者左右两边都不是 "w" 范围时的字符缝隙 |
2> 在表达式中有特殊意义,需要添加 "" 才能匹配该字符本身的字符汇总
字符
说明
匹配输入字符串的开始位置。要匹配 "^" 字符本身,请使用 "^"
匹配输入字符串的结尾位置。要匹配 "$" 字符本身,请使用 "$"
标记一个子表达式的开始和结束位置。要匹配小括号,请使用 "(" 和 ")"
[ ]
用来自定义能够匹配 '多种字符' 的表达式。要匹配中括号,请使用 "[" 和 "]"
{ }
修饰匹配次数的符号。要匹配大括号,请使用 "{" 和 "}"
匹配除了换行符(n)以外的任意一个字符。要匹配小数点本身,请使用 "."
修饰匹配次数为 0 次或 1 次。要匹配 "?" 字符本身,请使用 "?"
修饰匹配次数为至少 1 次。要匹配 "+" 字符本身,请使用 "+"
修饰匹配次数为 0 次或任意次。要匹配 "*" 字符本身,请使用 "*"
左右两边表达式之间 "或" 关系。匹配 "|" 本身,请使用 "|"
四、在ABAP中的应用
规则终于写完了!其实和其他编程语言规则差不多啦!下面结合ABAP讲讲怎么使用吧,Let’s GO!
不过需要注意,SAP只能是ECC6或者更高版本才可以使用正则(ABAP supports POSIX regular expressions as of Release 7.00)
在ABAP中定义了两个类来实现相应功能,分别是
CL_ABAP_REGEX regex就是regular expression的缩写,里面的方法不是很多,可能用到的也就只有构造方法和REATE_MATCHER这个方法。
CL_ABAP_MATCHER matcher匹配的意思,也就是说所有的匹配规则都和它有关,里面具体方法,se24去查看
其实正则表达式的应用无外乎三种:验证(是否符合规则)、查找(包含提取)、替换
1、验证
实例1
输出结果:ISNOTNUMBER |
解释:CL_ABAP_MATCHER有一个静态方法,直接进行匹配。
2、查找
实例2
输出结果:http://www.cnblogs.com/VerySky/admin/EditPosts.aspx?opt=1 |
解释:
- 创建match实例(创建规则),构造方法中有pattern参数输入规则,IGNORE_CASE是否忽略大小写,SIMPLE_REGEX是否使用简单规则(具体参见F1帮助文档),
B.在实例中有FIND_ALL(),FIND_NEXT()方法,可以用来查找。
这个方法是不是太麻烦了啊,不急有简单的方法,其实就是字符串处理中用到的。
实例3
输出结果: 11 3 24 3 |
实例4
输出结果: 我啊 们 |
解释:大家都知道英文字母是单字节的,中文是双字节的,但是在ABAP里面用strlen等方法是区别不出单双字节的,这个实例中讲的不失为一个很好的办法。
3、替换
输出结果:
REPLACEBEFORE: hubinshishuibuzhidao
REPLACECOUNTIS:2
REPLACEAFTER: hubinshishuibuzhidao
大家肯定会说了,字符串前后没有没替换啊。注意修改的不是W_TEXT本身,他将修改后的值放到了MATCHER->TEXT即match类实例的属性里面,我们只需令W_TEXT = MATCHER->TEXT即可。
修改后
同样这里也有简单方法,字符串处理中的方法也是支持正则的
实例5
输出结果: -dfxfdxd- |
4、方法语句总结
类结
CL_ABAP_MATCHER类里的重要方法
字符串处理中,支持正则的语句
五、补充
这里给出ABAP F1帮助中给出的一个特殊字符的列表,很有用的
Special Characters in Regular Expressions
The following tables summarize the special characters in regular expressions:
Escape character
Meaning |
|
Escape character for special characters |
Special character for single character strings
Placeholder for any single character |
||
C |
d |
Placeholder for any single digit |
D |
Placeholder for any character other than a digit |
|
l |
Placeholder for any lower-case letter |
|
L |
Placeholder for any character other than a lower-case letter |
|
s |
Placeholder for a blank character |
|
S |
Placeholder for any character other than a blank character |
|
u |
Placeholder for any upper-case letter |
|
U |
Placeholder for any character other than an upper-case letter |
|
w |
Placeholder for any alphanumeric character including_ |
|
W |
Placeholder for any non-alphanumeric character except for_ |
|
[ ] |
Definition of a value set for single characters |
|
[^ ] |
Negation of a value set for single characters |
|
[ - ] |
Definition of a range in a value set for single characters |
|
[ [:alnum:] ] |
Description of all alphanumeric characters in a value set |
|
[ [:alpha:] ] |
Description of all letters in a value set |
|
[ [:blank:] ] |
Description for blank characters and horizontal tabulators in a value set |
|
[ [:cntrl:] ] |
Description of all control characters in a value set |
|
[ [:digit:] ] |
Description of all digits in a value set |
|
[ [:graph:] ] |
Description of all graphic special characters in a value set |
|
[ [:lower:] ] |
Description of all lower-case letters in a value set |
|
[ [:print:] ] |
Description of all displayable characters in a value set |
|
[ [:punct:] ] |
Description of all punctuation characters in a value set |
|
[ [:space:] ] |
Description of all blank characters,tabulators,and carriage feeds in a value set |
|
[ [:unicode:] ] |
Description of all Unicode characters in a value set with a code larger than 255 |
|
[ [:upper:] ] |
Description of all upper-case letters in a value set |
|
[ [:word:] ] |
Description of all alphanumeric characters in a value set,including_ |
|
[ [:xdigit:] ] |
Description of all hexadecimal digits in a value set |
|
a f n r t v |
Diverse platform-specific control characters |
|
[..] |
Reserved for later enhancements |
|
[==] |
Reserved for later enhancements |
Special characters for character string patterns
Concatenation ofnsingle characters |
||||||||||||||||||||||||||
{n,m} |
Concatenation of at leastnand a maximum ofmsingle characters |
|||||||||||||||||||||||||
? |
One or no single characters |
|||||||||||||||||||||||||
* |
Concatenation of any number of single characters including 'no characters' |
|||||||||||||||||||||||||
*? |
+ |
Concatenation of any number of single characters excluding 'no characters' |
||||||||||||||||||||||||
+? |
| |
Linking of two alternative expressions |
||||||||||||||||||||||||
( ) |
Definition of subgroups with registration |
|||||||||||||||||||||||||
(?: ) |
Definition of subgroups without registration |
|||||||||||||||||||||||||
1,2,3... |
Placeholder for the register of subgroups |
|||||||||||||||||||||||||
Q...E |
Definition of a string of literal characters |
|||||||||||||||||||||||||
(?...) |
Special characters for search strings
Special characters for replacement texts
从上面的列表可以看出,ABAP中对“非贪婪模式”(ABAP啊,你不支持啊,你太贪婪了)和“反向预搜索”暂不支持,希望以后能够赶紧扩展功能吧,毕竟很强大的说。 正则表达式是需要反复修改,最后才能找到最匹配的规则的,为此ABAP Program里也提供了一个,测试用得小程序,SE38里找DEMO_REGEX_TOY运行即可。 在ABAP培训资料里面有一个很有意思的表达式,大家有兴趣可以看一下它能匹配什么文字 ^(?=d)(?:(?:31(?!.(?:0?[2469]|11))|(?:30 |29)(?!.0?2)|29(?=.0?2.(?:(?:(?:1[6-9]|[2 -9]d)?(?:0[48]|[2468][048]|[13579][26])| (?:(?:16|[2468][048]|[3579][26])00)))(?: x20|$))|(?:2[0-8]|1d|0?[1-9]))([-./])(?: 1[012]|0?[1-9])1(?:1[6-9]|[2-9]d)?dd( ?:(?=x20d)x20|$))?(((0?[1-9]|1[012])(: [0-5]d){0,2}(x20[AP]M))|([01]d|2[0-3]) (:[0-5]d){1,2})?$ |
以下附上网上的一些资料:
表达式全集
正则表达式有多种不同的风格。下表是在PCRE中元字符及其在正则表达式上下文中的行为的一个完整列表:
字符 |
描述 |
|
将下一个字符标记为一个特殊字符、或一个原义字符、或一个向后引用、或一个八进制转义符。例如,“ |
||
^ |
匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“ |
|
$ |
匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“ |
|
* |
匹配前面的子表达式零次或多次。例如,zo*能匹配“ |
|
+ |
匹配前面的子表达式一次或多次。例如,“ ? |
匹配前面的子表达式零次或一次。例如,“ |
{n} |
n是一个非负整数。匹配确定的n次。例如,“ |
|
{n,} |
n是一个非负整数。至少匹配n次。例如,“ |
|
m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“ |
||
当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“ |
||
. |
匹配除“ |
|
(pattern) |
匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“ |
|
(?:pattern) |
匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用或字符“ |
|
(?=pattern) |
正向预查,在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“ |
|
(?!pattern) |
负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如“ |
|
x|y |
匹配x或y。例如,“ |
|
[xyz] |
字符集合。匹配所包含的任意一个字符。例如,“ |
|
[^xyz] |
负值字符集合。匹配未包含的任意字符。例如,“ |
|
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,“ |
|
[^a-z] |
负值字符范围。匹配任何不在指定范围内的任意字符。例如,“ |
|
b |
匹配一个单词边界,也就是指单词和空格间的位置。例如,“ |
|
B |
匹配非单词边界。“ |
|
cx |
匹配由x指明的控制字符。例如,cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“ |
|
d |
匹配一个数字字符。等价于[0-9]。 |
|
D |
匹配一个非数字字符。等价于[^0-9]。 |
|
f |
匹配一个换页符。等价于x0c和cL。 |
|
n |
匹配一个换行符。等价于x0a和cJ。 |
|
r |
匹配一个回车符。等价于x0d和cM。 |
|
s |
匹配任何空白字符,包括空格、制表符、换页符等等。等价于[fnrtv]。 |
|
S |
匹配任何非空白字符。等价于[^fnrtv]。 |
|
t |
匹配一个制表符。等价于x09和cI。 |
|
v |
匹配一个垂直制表符。等价于x0b和cK。 |
|
w |
匹配包括下划线的任何单词字符。等价于“ |
|
W |
匹配任何非单词字符。等价于“ |
|
xn |
匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,“ |
|
num |
匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“ |
|
n |
标识一个八进制转义值或一个向后引用。如果n之前至少n个获取的子表达式,则n为向后引用。否则,如果n为八进制数字(0-7),则n为一个八进制转义值。 |
|
nm |
标识一个八进制转义值或一个向后引用。如果nm之前至少有nm个获得子表达式,则nm为向后引用。如果nm之前至少有n个获取,则n为一个后跟文字m的向后引用。如果前面的条件都不满足,若n和m均为八进制数字(0-7),则nm将匹配八进制转义值nm。 |
|
nml |
如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml。 |
|
un |
匹配n,其中n是一个用四个十六进制数字表示的Unicode字符。例如,u00A9匹配版权符号(?)。 |
常用的正则表达式
正则表达式用于字符串处理、表单验证等场合,实用高效。现将一些常用的表达式收集于此,以备不时之需。
用户名:/^[a-z0-9_-]{3,16}$/
密码:/^[a-z0-9_-]{6,18}$/
十六进制值:/^#?([a-f0-9]{6}|[a-f0-9]{3})$/
电子邮箱:/^([a-z0-9_.-]+)@([da-z.-]+).([a-z.]{2,6})$/
URL:/^(https?://)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$/
IP 地址:/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
HTML 标签:/^<([a-z]+)([^<]+)*(?:>(.*)</1>|s+/>)$/
Unicode编码中的汉字范围:/^[u4e00-u9fa5],{0,}$/
匹配中文字符的正则表达式: [u4e00-u9fa5]
评注:匹配中文还真是个头疼的事,有了这个表达式就好办了
匹配双字节字符(包括汉字在内):[^x00-xff]
评注:可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1)
匹配空白行的正则表达式:ns*r
评注:可以用来删除空白行
匹配HTML标记的正则表达式:<(S*?)[^>]*>.*?</1>|<.*? />
评注:网上流传的版本太糟糕,上面这个也仅仅能匹配部分,对于复杂的嵌套标记依旧无能为力
匹配首尾空白字符的正则表达式:^s*|s*$
评注:可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式
匹配Email地址的正则表达式:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
评注:表单验证时很实用
匹配网址URL的正则表达式:[a-zA-z]+://[^s]*
评注:网上流传的版本功能很有限,上面这个基本可以满足需求
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
评注:表单验证时很实用
匹配国内电话号码:d{3}-d{8}|d{4}-d{7}
评注:匹配形式如 0511-4405222 或 021-87888822
匹配腾讯QQ号:[1-9][0-9]{4,}
评注:腾讯QQ号从10000开始
匹配中国大陆邮政编码:[1-9]d{5}(?!d)
评注:中国大陆邮政编码为6位数字
匹配身份证:d{15}|d{18}
评注:中国大陆的身份证为15位或18位
匹配ip地址:d+.d+.d+.d+
评注:提取ip地址时有用
匹配特定数字:
^[1-9]d*$ //匹配正整数
^-[1-9]d*$ //匹配负整数
^-?[1-9]d*$ //匹配整数
^[1-9]d*|0$ //匹配非负整数(正整数 + 0)
^-[1-9]d*|0$ //匹配非正整数(负整数 + 0)
^[1-9]d*.d*|0.d*[1-9]d*$ //匹配正浮点数
^-([1-9]d*.d*|0.d*[1-9]d*)$ //匹配负浮点数
^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$ //匹配浮点数
^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$ //匹配非负浮点数(正浮点数 + 0)
^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$ //匹配非正浮点数(负浮点数 + 0)
评注:处理大量数据时有用,具体应用时注意修正
匹配特定字符串:
^[A-Za-z]+$ //匹配由26个英文字母组成的字符串
^[A-Z]+$ //匹配由26个英文字母的大写组成的字符串
^[a-z]+$ //匹配由26个英文字母的小写组成的字符串
^[A-Za-z0-9]+$ //匹配由数字和26个英文字母组成的字符串
^w+$ //匹配由数字、26个英文字母或者下划线组成的字符串
如何写出高效率的正则表达式
如果纯粹是为了挑战自己的正则水平,用来实现一些特效(例如使用正则表达式计算质数、解线性方程),效率不是问题;如果所写的正则表达式只是为了满足一两次、几十次的运行,优化与否区别也不太大。但是,如果所写的正则表达式会百万次、千万次地运行,效率就是很大的问题了。我这里总结了几条提升正则表达式运行效率的经验(工作中学到的,看书学来的,自己的体会),贴在这里。如果您有其它的经验而这里没有提及,欢迎赐教。
为行文方便,先定义两个概念。
误匹配:指正则表达式所匹配的内容范围超出了所需要范围,有些文本明明不符合要求,但是被所写的正则式“击中了”。例如,如果使用d{11}来匹配11位的手机号,d{11}不单能匹配正确的手机号,它还会匹配98765432100这样的明显不是手机号的字符串。我们把这样的匹配称之为误匹配。
漏匹配:指正则表达式所匹配的内容所规定的范围太狭窄,有些文本确实是所需要的,但是所写的正则没有将这种情况囊括在内。例如,使用d{18}来匹配18位的身份证号码,就会漏掉结尾是字母X的情况。
写出一条正则表达式,既可能只出现误匹配(条件写得极宽松,其范围大于目标文本),也可能只出现漏匹配(只描述了目标文本中多种情况种的一种),还可能既有误匹配又有漏匹配。例如,使用w+.com来匹配.com结尾的域名,既会误匹配abc_.com这样的字串(合法的域名中不含下划线,w包含了下划线这种情况),又会漏掉ab-c.com这样的域名(合法域名中可以含中划线,但是w不匹配中划线)。
精准的正则表达式意味着既无误匹配且无漏匹配。当然,现实中存在这样的情况:只能看到有限数量的文本,根据这些文本写规则,但是这些规则将会用到海量的文本中。这种情况下,尽可能地(如果不是完全地)消除误匹配以及漏匹配,并提升运行效率,就是我们的目标。本文所提出的经验,主要是针对这种情况。
掌握语法细节。正则表达式在各种语言中,其语法大致相同,细节各有千秋。明确所使用语言的正则的语法的细节,是写出正确、高效正则表达式的基础。例如,perl中与w等效的匹配范围是[a-zA-Z0-9_];perl正则式不支持肯定逆序环视中使用可变的重复(variable repetition inside lookbehind,例如(?<=.*)abc),但是.Net语法是支持这一特性的;又如,JavaScript连逆序环视(Lookbehind,如(?<=ab)c)都不支持,而perl和python是支持的。《精通正则表达式》第3章《正则表达式的特性和流派概览》明确地列出了各大派系正则的异同,这篇文章也简要地列出了几种常用语言、工具中正则的比较。对于具体使用者而言,至少应该详细了解正在使用的那种工作语言里正则的语法细节。
先粗后精,先加后减。使用正则表达式语法对于目标文本进行描述和界定,可以像画素描一样,先大致勾勒出框架,再逐步在局步实现细节。仍举刚才的手机号的例子,先界定d{11},总不会错;再细化为1[358]d{9},就向前迈了一大步(至于第二位是不是3、5、8,这里无意深究,只举这样一个例子,说明逐步细化的过程)。这样做的目的是先消除漏匹配(刚开始先尽可能多地匹配,做加法),然后再一点一点地消除误匹配(做减法)。这样有先有后,在考虑时才不易出错,从而向“不误不漏”这个目标迈进。
留有余地。所能看到的文本sample是有限的,而待匹配检验的文本是海量的,暂时不可见的。对于这样的情况,在写正则表达式时要跳出所能见到的文本的圈子,开拓思路,作出“战略性前瞻”。例如,经常收到这样的垃圾短信:“发*票”、“发#漂”。如果要写规则屏蔽这样烦人的垃圾短信,不但要能写出可以匹配当前文本的正则表达式 发[*#](?:票|漂),还要能够想到 发.(?:票|漂|飘)之类可能出现的“变种”。这在具体的领域或许会有针对性的规则,不多言。这样做的目的是消除漏匹配,延长正则表达式的生命周期。
明确。具体说来,就是谨慎用点号这样的元字符,尽可能不用星号和加号这样的任意量词。只要能确定范围的,例如w,就不要用点号;只要能够预测重复次数的,就不要用任意量词。例如,写析取twitter消息的脚本,假设一条消息的xml正文部分结构是<span class=”msg”>…</span>且正文中无尖括号,那么<span class=”msg”>[^<]{1,480}</span>这种写法的思路要好于<span class=”msg”>.*</span>,原因有二:一是使用[^<],它保证了文本的范围不会超出下一个小于号所在的位置;二是明确长度范围,{1,480},其依据是一条twitter消息大致能的字符长度范围。当然,480这个长度是否正确还可推敲,但是这种思路是值得借鉴的。说得狠一点,“滥用点号、星号和加号是不环保、不负责任的做法”。
不要让稻草压死骆驼。每使用一个普通括号()而不是非捕获型括号(?:…),就会保留一部分内存等着你再次访问。这样的正则表达式、无限次地运行次数,无异于一根根稻草的堆加,终于能将骆驼压死。养成合理使用(?:…)括号的习惯。
宁简勿繁。将一条复杂的正则表达式拆分为两条或多条简单的正则表达式,编程难度会降低,运行效率会提升。例如用来消除行首和行尾空白字符的正则表达式s/^s+|s+$//g;,其运行效率理论上要低于s/^s+//g; s/s+$//g; 。这个例子出自《精通正则表达式》第五章,书中对它的评论是“它几乎总是最快的,而且显然最容易理解”。既快又容易理解,何乐而不为?工作中我们还有其它的理由要将C==(A|B)这样的正则表达式拆为A和B两条表达式分别执行。例如,虽然A和B这两种情况只要有一种能够击中所需要的文本模式就会成功匹配,但是如果只要有一条子表达式(例如A)会产生误匹配,那么不论其它的子表达式(例如B)效率如何之高,范围如何精准,C的总体精准度也会因A而受到影响。
巧妙定位。有时候,我们需要匹配的the,是作为单词的the(两边有空格),而不是作为单词一部分的t-h-e的有序排列(例如together中的the)。在适当的时候用上^,$,b等等定位锚点,能有效提升找到成功匹配、淘汰不成功匹配的效率。
附上资料:
1、本文word版:http://115.com/file/c2fac2o9
2、正则表达式ABAP官方资料:http://115.com/file/beucnm53
3、正则表达式查阅文档:http://115.com/file/c2fackc0
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!