Crossin的编程教室

标题: 【Python 第59课】 正则表达式(5) [打印本页]

作者: crossin先生    时间: 2013-9-29 16:27
标题: 【Python 第59课】 正则表达式(5)

听说有人已经开始国庆假期了,甚至还有人中秋之后就请了年假一休到底,表示羡慕嫉妒恨!今天发完这课,我也要进入休假状态,谁也别拦着我。


来说上次的习题:

(021)88776543

010-55667890

02584453362

0571 66345673


一个可以匹配出所有结果的表达式是

\(?0\d{2,3}[) -]?\d{7,8}


解释一下:

\(?

()在正则表达式里也有着特殊的含义,所以要匹配字符"(",需要用"\("。?表示这个括号是可有可无的。


0\d{2,3}

区号,0xx或者0xxx


[) -]?

在区号之后跟着的可能是")"、" "、"-",也可能什么也没有。


\d{7,8}

7或8位的电话号码


可是,这个表达式虽然能匹配出所有正确的数据(一般情况下,这样已经足够),但理论上也会匹配到错误的数据。因为()应当是成对出现的,表达式中对于左右两个括号并没有做关联处理,例如(02188776543这样的数据也是符合条件的。


我们可以用正则表达式中的“|”符号解决这种问题。“|”相当于python中“or”的作用,它连接的两个表达式,只要满足其中之一,就会被算作匹配成功。


于是我们可以把()的情况单独分离出来:

\(0\d{2,3}\)\d{7,8}


其他情况:

0\d{2,3}[ -]?\d{7,8}


合并:

\(0\d{2,3}\)\d{7,8}|0\d{2,3}[ -]?\d{7,8}



使用“|”时,要特别提醒注意的是不同条件之间的顺序。匹配时,会按照从左往右的顺序,一旦匹配成功就停止验证后面的规则。假设要匹配的电话号码还有可能是任意长度的数字(如一些特殊的服务号码),你应该把

|\d+

这个条件加在表达式的最后。如果放在最前面,某些数据就可能会被优先匹配为这一条件。你可以写个测试用例体会一下两种结果的不同。



关于正则表达式,我们已经讲了5篇,介绍了正则表达式最最皮毛的一些用法。接下来,这个话题要稍稍告一段落。推荐一篇叫做《正则表达式30分钟入门教程》的文章(直接百度一下就能找到,我也会转到论坛上),想要对正则表达式进一步学习的同学可以参考。这篇教程是个标题党,里面涉及了正则表达式较多的内容,30分钟绝对看不完。


好了,祝大家过个欢脱的长假,好好休息,多陪家人。



#==== Crossin的编程教室 ====#
微信ID:crossincode
论坛:http://crossin.me
QQ群:156630350

面向零基础初学者的编程课
每天5分钟,轻松学编程



作者: nsm1168    时间: 2013-9-29 19:41
不错,昨天也在学习 《正则表达式30分钟入门教程》 这个教程了。
作者: michael    时间: 2013-10-2 00:40
学习了
作者: 跑跑慢慢    时间: 2013-10-6 11:50
正在联系中
作者: QQ_321CD6    时间: 2014-6-30 20:30
crossin老师您好 有一个问题想请教您一下
老师给出的答案是 \(?0\d{2,3}[) -]?\d{7,8}
我在自己测试的时候 不小心把第二个问号前[]里的内容写成了[)- ]
也就是把空格和-的位置调换了 (\(?0\d{2,3}[)- ]?\d{7,8}) 就出现了下面这样的错误

Traceback (most recent call last):
  File "lesson58.py", line 4, in <module>
    pattern = re.compile(r'\(?0\d{2,3}\)[)- ]?\d{7,8}|0\d{2,3}[ -]?\d{7,8}|d+')
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 190, in compile
    return _compile(pattern, flags)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 242, in _compile
    raise error, v # invalid expression
sre_constants.error: bad character range

请问这是为什么呢? 在写正则表达式的时候 对于表达式里面的选项的顺序是有要求的么? 谢谢
作者: crossin先生    时间: 2014-7-1 11:29
QQ_321CD6 发表于 2014-6-30 20:30
crossin老师您好 有一个问题想请教您一下
老师给出的答案是 \(?0\d{2,3}[) -]?\d{7,8}
我在自己测试的时候  ...

查了一下。减号-在中括号[]里是有特殊含义的
[a-z]是表示从字符a到字符z的所有字符
但[z-a]就会报错,因为a在z前面
而[)- ]表示从)到 的所有字符,而)的字符值又比空格大,所以就报错了
作者: QQ_321CD6    时间: 2014-7-1 22:27
crossin先生 发表于 2014-7-1 11:29
查了一下。减号-在中括号[]里是有特殊含义的
[a-z]是表示从字符a到字符z的所有字符
但[z-a]就会报错,因 ...

讲得十分详细, 谢谢. 麻烦您了
作者: liu-pengfei    时间: 2014-9-28 23:54
又学习了。
作者: lincoln    时间: 2015-7-9 20:26
老师您好,发现一个问题,不知道怎么解决
(021)88776543
010-55667890
02584453362
0571 66345673
用下列表达式匹配
\(0\d{2,3}\)\d{7,8}|0\d{2,3}[ -]?\d{7,8}
第三个电话号码,会在0之后先匹配3位,然后后面再匹配8位,没办法先匹配2位,再匹配7位,导致最后一个号码不能匹配,应该描述清楚了吧?
作者: crossin先生    时间: 2015-7-10 00:31
lincoln 发表于 2015-7-9 20:26
老师您好,发现一个问题,不知道怎么解决
(021)88776543
010-55667890

它就是这样可以匹配啊,如果你强行要匹配2+7,就不能给3和8的选项,不然都会尽可能匹配的
作者: lincoln    时间: 2015-7-10 23:20
crossin先生 发表于 2015-7-10 00:31
它就是这样可以匹配啊,如果你强行要匹配2+7,就不能给3和8的选项,不然都会尽可能匹配的 ...

原来是我把所有号码连一起写了,彼此加了空格就好了。
还是要问一下,号码收尾连在一起就匹配错了,想了好久无果。
" (021)88776543010-55667890025844533620571 66345673 "
结果是['(021)88776543'  '010-55667890'  '025844533620']

作者: crossin先生    时间: 2015-7-11 18:11
lincoln 发表于 2015-7-10 23:20
原来是我把所有号码连一起写了,彼此加了空格就好了。
还是要问一下,号码收尾连在一起就匹配错了,想了 ...

因为同等情况下,会优先匹配更长的结果,就把0也给匹配到前一次结果里了
作者: 周末晒被子    时间: 2016-1-13 03:06
本帖最后由 周末晒被子 于 2016-1-13 03:09 编辑

看了一遍《正则表达式30分钟教程》。看懂70%左右。
先生已经讲过的部分不难,可以很快过;
“零宽断言”(和负向零宽断言)部分,有一些理解困难;
“处理选项”部分,好像不难,没有操作的话等于没看;
“平衡组/递归匹配”这部分,思想方法介绍地很明白,但是给出的例子就看不明白了,应该是文章因为有默认前置知识我不知道。

只想说谢谢先生啊,让编程学起来更容易。
作者: crossin先生    时间: 2016-1-13 10:07
周末晒被子 发表于 2016-1-13 03:06
看了一遍《正则表达式30分钟教程》。看懂70%左右。
先生已经讲过的部分不难,可以很快过;
“零宽断言”( ...


作者: exchen    时间: 2016-4-14 15:58

作者: Yumiao_HyunMin    时间: 2016-6-30 17:21
先生好!
您上面提到\(?0\d{2,3}[) -]?\d{7,8}  在这里面[) -]? 表示的是区号之后跟着的可能是")"、" "、"-",也可能什么也没有
我刚一看到这里总感觉是区号后面 )- 的意思是要么同时出现,要么这俩符号都没有。。。
比如(010)-92891381 匹配,但是(010)92891381 就不匹配了
好奇怪。。。
作者: crossin先生    时间: 2016-6-30 21:40
Yumiao_HyunMin 发表于 2016-6-30 17:21
先生好!
您上面提到\(?0\d{2,3}[) -]?\d{7,8}  在这里面[) -]? 表示的是区号之后跟着的可能是")"、" "、"- ...

中括号里面的内容表示选其中任一个
作者: Yumiao_HyunMin    时间: 2016-7-1 09:16
crossin先生 发表于 2016-6-30 21:40
中括号里面的内容表示选其中任一个

好的明白了!!
作者: marvinmi    时间: 2018-10-21 15:09
  1. import re

  2. Num = '(021)88776543 010-55667890 02584453362 0571 66345673f'
  3. m = re.findall(r'\(?0\d{2,3}[) -]?\d{7,8}]', Num)
  4. print(m)
复制代码
先生好,请问我这个代码为什么输出的是空啊
作者: crossin先生    时间: 2018-10-21 21:54
marvinmi 发表于 2018-10-21 15:09
先生好,请问我这个代码为什么输出的是空啊

最后多个中括号]吧
作者: marvinmi    时间: 2018-10-22 19:14
crossin先生 发表于 2018-10-21 21:54
最后多个中括号]吧

先生正解,谢谢先生
作者: jaxon    时间: 2019-5-17 17:07
本帖最后由 jaxon 于 2019-5-17 17:12 编辑

import re
text = "(021)88776543和规范化和010-55667890规范化个02584453362广发华福0571 66345673个回合6565,UUID"

n = re.findall(r"[\(0]\d{2,3}\D{0,1}\d{8}", text)
if n:
    #print(m)
    print(n)
else:
    print('not match')
   
先生好,这是我自己想的课后练习答案,能正确输出所有号码,
['(021)88776543', '010-55667890', '02584453362', '0571 66345673']
但是改为n = re.findall(r"^[\(0]\d{2,3}\D{0,1}\d{8}", text)
只能输出第一个号码
['(021)88776543']
改为n = re.findall(r"^[\(0]\d{2,3}\D{0,1}\d{8}$", text)
输出not match
不太懂这个^和$的用法。
作者: jaxon    时间: 2019-5-17 17:37
jaxon 发表于 2019-5-17 17:07
import re
text = "(021)88776543和规范化和010-55667890规范化个02584453362广发华福0571 66345673个回合6 ...

^表示整个字符串必须以给定的格式开头,否则就无匹配
$表示字符串必须以给定的格式结尾,否则就无匹配
^,$一起用表示整个字符串就是给定的格式
不知道对不对
作者: crossin先生    时间: 2019-5-18 14:28
jaxon 发表于 2019-5-17 17:37
^表示整个字符串必须以给定的格式开头,否则就无匹配
$表示字符串必须以给定的格式结尾,否则就无匹配
^, ...






欢迎光临 Crossin的编程教室 (https://bbs.crossincode.com/) Powered by Discuz! X2.5