Crossin的编程教室

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

作者: crossin先生    时间: 2013-9-18 00:21
标题: 【Python 第56课】 正则表达式(2)
有同学问起昨天那段测试代码里的问题,我来简单说一下。

1.
r"hi"

这里字符串前面加了r,是raw的意思,它表示对字符串不进行转义。为什么要加这个?你可以试试print "\bhi"和r"\bhi"的区别。
>>> print "\bhi"
hi
>>> print r"\bhi"
\bhi

可以看到,不加r的话,\b就没有了。因为python的字符串碰到“\”就会转义它后面的字符。如果你想在字符串里打“\”,则必须要打“\\”。
>>> print "\\bhi"
\bhi

这样的话,我们的正则表达式里就会多出很多“\”,让本来就已经复杂的字符串混乱得像五仁月饼一般。但加上了“r”,就表示不要去转义字符串中的任何字符,保持它的原样。

2.
re.findall(r"hi", text)

re是python里的正则表达式模块。findall是其中一个方法,用来按照提供的正则表达式,去匹配文本中的所有符合条件的字符串。返回结果是一个包含所有匹配的list。

3.
今天主要说两个符号“.”和“*”,顺带说下“\S”和“?”。
“.”在正则表达式中表示除换行符以外的任意字符。在上节课提供的那段例子文本中:
Hi, I am Shirley Hilton. I am his wife.

如果我们用“i.”去匹配,就会得到
['i,', 'ir', 'il', 'is', 'if']

你若是暴力一点,也可以直接用“.”去匹配,看看会得到什么。

与“.”类似的一个符号是“\S”,它表示的是不是空白符的任意字符。注意是大写字符S。

4.
在很多搜索中,会用“?”表示任意一个字符,“*”表示任意数量连续字符,这种被称为通配符。但在正则表达式中,任意字符是用“.”表示,而“*”则不是表示字符,而是表示数量:它表示前面的字符可以重复任意多次(包括0次),只要满足这样的条件,都会被表达式匹配上。

结合前面的“.*”,用“I.*e”去匹配,想一下会得到什么结果?
['I am Shirley Hilton. I am his wife']

是不是跟你想的有些不一样?也许你会以为是
['I am Shirle', 'I am his wife']

这是因为“*”在匹配时,会匹配尽可能长的结果。如果你想让他匹配到最短的就停止,需要用“.*?”。如“I.*?e”,就会得到第二种结果。这种匹配方式被称为懒惰匹配,而原本尽可能长的方式被称为贪婪匹配。

最后留一道习题:
从下面一段文本中,匹配出所有s开头,e结尾的单词。

site sea sue sweet see case sse ssee loses


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

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


作者: 匠逍之岿    时间: 2013-9-18 11:02
import re
text = 'site sea sue sweet see case sse ssee loses'
m = re.findall(r'\bs\S*?e\b',text)
print m

作者: jpjlqone    时间: 2013-9-18 13:21
先生,我想在win下模拟鼠标中键的滚动行为,没能找到适用的模块。希望能提供点信息。
作者: crossin先生    时间: 2013-9-19 00:49
jpjlqone 发表于 2013-9-18 13:21
先生,我想在win下模拟鼠标中键的滚动行为,没能找到适用的模块。希望能提供点信息。 ...

pygame的pygame.MOUSEBUTTONDOWN可以监听鼠标滚轮事件
作者: crossin先生    时间: 2013-9-19 00:50
jpjlqone 发表于 2013-9-18 13:21
先生,我想在win下模拟鼠标中键的滚动行为,没能找到适用的模块。希望能提供点信息。 ...

哦,你说的是模拟,参考一下这个看看
http://blog.csdn.net/sunyonggao/article/details/8121061
作者: jpjlqone    时间: 2013-9-19 10:09
crossin先生 发表于 2013-9-19 00:50
哦,你说的是模拟,参考一下这个看看
http://blog.csdn.net/sunyonggao/article/details/8121061 ...

老师中秋节好!
这个文章我看过,它能够模拟鼠标中键点下去,然后移动鼠标,最后中键抬起(方法一)。
但是无法实现中键真正意义的“滚动”行为。(虽然表面效果一样,但是有款游戏,是根据滚轮物理圈数算距离的,方法一就无效果了)
作者: aison    时间: 2013-9-19 12:34
import re
text = 'site sea sue sweet see case sse ssee loses'
pattern = re.compile(r'\bs\S*?e\b')
m = pattern.findall(text)
print m

ps:上面的代码在搜索的文本内容比较大时,性能会比2楼的速度上要快。
作者: crossin先生    时间: 2013-9-20 23:47
aison 发表于 2013-9-19 12:34
import re
text = 'site sea sue sweet see case sse ssee loses'
pattern = re.compile(r'\bs\S*?e\b')

嗯,是的
作者: crossin先生    时间: 2013-9-20 23:56
jpjlqone 发表于 2013-9-19 10:09
老师中秋节好!
这个文章我看过,它能够模拟鼠标中键点下去,然后移动鼠标,最后中键抬起(方法一)。
但 ...

win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL,0,0,-20,win32con.WHEEL_DELTA)

http://blog.sina.com.cn/s/blog_53f023270101ors4.html
作者: jpjlqone    时间: 2013-9-21 00:34
crossin先生 发表于 2013-9-20 23:56
win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL,0,0,-20,win32con.WHEEL_DELTA)

http://blog.sina.co ...

搞定,谢谢。
作者: Myk_cc    时间: 2013-9-21 20:01
本帖最后由 Myk_cc 于 2013-9-21 20:07 编辑

同学在我电脑上使用的豌豆荚,自动保存了联系人,我将.vcf文件中的内容保存到文本文件中,然后用正则表达式将其中的电话号码提取出来。

请老师指点。
代码和图片在回复中



作者: Myk_cc    时间: 2013-9-21 20:06
本帖最后由 Myk_cc 于 2013-9-21 20:07 编辑
Myk_cc 发表于 2013-9-21 20:01
同学在我电脑上使用的豌豆荚,自动保存了联系人,我将.vcf文件中的内容保存到文本文件中,然后用正则表达式 ...
  1. #!/usr/bin/python

  2. import re

  3. f = open('file1.txt')
  4. s = f.read()
  5. str(s)
  6. m = re.findall(r"1.*?\n", s)
  7. f.close

  8. for i in m:
  9.     print i[0:10]
复制代码

QQ图片20130921195844.jpg (14.94 KB, 下载次数: 483)

QQ图片20130921195844.jpg


作者: crossin先生    时间: 2013-9-22 00:35
Myk_cc 发表于 2013-9-21 20:06

不错的,赞一下现学现用的学习方式!
作者: eep    时间: 2013-9-23 15:24
import re

text = 'site sea sue sweet see case sse ssee loses'
p = re.compile(r'\bs\w+e\b',re.X)
m = p.findall(text)
if m:
    print 'match!'
    print m
作者: fl0w    时间: 2013-9-25 14:35
神奇的正则表达式
作者: michael    时间: 2013-10-2 00:24
r'\bs\S*?e\b'
作者: 508490571    时间: 2014-3-17 23:36
  1. import re
  2. text1='site sea sue sweet see case sse ssee loses'
  3. w=text1.split(' ')
  4. h=str(w)
  5. n=re.findall(r'\bs.*?e\b',h)
  6. print n
复制代码
不用split的话  print结果中  sea sue  会连在一起。没有h=str(w)的话 又会报错TypeError: expected string or buffer
所以最终结果就是这样了,运行正确
作者: 文心雕龙    时间: 2014-5-17 14:52
\bs\S.*?e\b和\bs.*?e\b输出结果一样的,请问是不是可以理解为这几个符号有优先级?
作者: crossin先生    时间: 2014-5-18 15:10
文心雕龙 发表于 2014-5-17 14:52
\bs\S.*?e\b和\bs.*?e\b输出结果一样的,请问是不是可以理解为这几个符号有优先级? ...

这两个不完全一样。
前面加了个\S,其实相当于是先匹配一个非空白字符,然后再匹配任意数量字符。
如果有"se",那么前者无法匹配,后者可以。
作者: 脑子有音乐    时间: 2014-7-3 12:20
\bs\w*e\b
作者: liu-pengfei    时间: 2014-9-28 23:29
先生,r'\bs\S*?e\b'这样可以,但是r'\bs.*?e\b'这样,遇到"sad (有个空格)see"是不是匹配出"sad see"?
作者: robinlkm    时间: 2014-12-19 11:14
先生 您好
请问 如果要查找“/b” 内容 应该怎么,写?
谢谢~!
作者: crossin先生    时间: 2014-12-19 11:52
r"/b"
作者: sukiak    时间: 2015-4-5 10:10
老师,
import re
text = "Shirley  his"
m = re.findall(r'hi',text)
print m
出现的只有两个hi,而不是完整单词怎么办?
作者: crossin先生    时间: 2015-4-5 13:51
sukiak 发表于 2015-4-5 10:10
老师,
import re
text = "Shirley  his"

hi只能匹配到hi,如果你想匹配整个单词,得在前后加上匹配0~n个非空格字符的正则,如
\w*hi\w*
作者: 草办    时间: 2015-12-14 13:45
get
作者: catherinemic    时间: 2016-2-2 14:46
Crossin老师,想问一下,既然r'\bhi'表示非转译的原始字符‘\bhi',但是为什么re.findall(r'\bhi', text)的结果是能找到匹配,而refindall('\bhi',text)找不到匹配呢?如果我想在一段话中找\bhi,又该怎样写正则表达式呢?

作者: crossin先生    时间: 2016-2-2 23:00
catherinemic 发表于 2016-2-2 14:46
Crossin老师,想问一下,既然r'\bhi'表示非转译的原始字符‘\bhi',但是为什么re.findall(r'\bhi', text)的 ...

直接写'\bhi',\b就被转义了。
找\bhi的话,要防止\b作为特殊元字符去匹配,所以需要用
r"\\bhi"

作者: fangweiren    时间: 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果
  1. import re
  2. text = 'site sea sue sweet see case sse ssee loses'
  3. pattern = re.compile(r'\bs\S*?e\b')
  4. req = re.findall(pattern,text)
  5. print req
复制代码

作者: crossin先生    时间: 2016-2-3 22:27
fangweiren 发表于 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果

^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配
作者: crossin先生    时间: 2016-2-3 22:29
fangweiren 发表于 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果

^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配
作者: crossin先生    时间: 2016-2-3 22:33
fangweiren 发表于 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果

^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配
作者: crossin先生    时间: 2016-2-3 22:33
fangweiren 发表于 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果

^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配
作者: crossin先生    时间: 2016-2-3 22:34
fangweiren 发表于 2016-2-3 13:39
Cross先生,为什么不能用^表示开头,$表示结尾,试了好多,输不出结果

^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配
作者: fangweiren    时间: 2016-2-4 10:23
crossin先生 发表于 2016-2-3 22:34
^是表示整个字符串的开头,$是整个字符串的结尾,同时加了这两个,那除非整串完全匹配 ...

嗯嗯,后来想通了,^$是匹配真个字符串,现在确是在一个字符串中匹配,谢谢先生
作者: catherinemic    时间: 2016-2-4 10:53
crossin先生 发表于 2016-2-2 23:00
直接写'\bhi',\b就被转义了。
找\bhi的话,前面就要用r

谢谢先生,大概明白了~~
作者: xqqxjnt1988    时间: 2016-2-4 14:02
crossing先生,请帮我看看这个问题啊,谢谢

#!/usr/bin/python
#coding=utf-8
#author=xuqq
#下面这个程序是练习正则表达式的
#从下面一段文本中,匹配出所有s开头,e结尾的单词。


import re

def main():
    text = "site sea sue sweet see case sse ssee loses"
    #m = re.findall("\bs.*e\b", text)            #返回结果是一个包含所有匹配的list。贪婪匹配
    #m = re.findall(r"\bs\S*?e\b",text)             #返回结果是匹配到最短的就停止,懒惰匹配
    m = re.findall(r'\bs\S*?e\b',text)
    if m:
        print m
    else:
        print 'not match'
    #print "\bhi"
    #print r"\bhi"             #加r是为了把所有字都打出来,不转义。因为python的字符串碰到“\”就会转义它后面的字符。如果你想在字符串里打“\”,则必须要打“\\”。
    print "我们看看转义了吗,加了r之后:\t", r"\bs\S*?e\b"        #打出来\b什么的都在
   
if __name__=='__main__':
    main()
   
#“.”在正则表达式中表示:  除换行符以外的任意字符。
#“\S”,它表示:           不是空白符的任意字符。注意是大写字符S。
#“*”表示:                数量:它表示前面的字符可以重复任意多次(包括0次)

输出下来的问题如下:
print "我们看看转义了吗,加了r之后:\t", r"\bs\S*?e\b"        #打出来\b什么的都在

m = re.findall(r"\bs\S*?e\b",text)             #返回结果是匹配到最短的就停止,懒惰匹配

同样的r
放在print里面,就是照实打出来

r放在正则表达式里 ,\b \S什么的就不是照实打了,还是转义了

m= re.findall(r"\bs\S*?e\b",text)   “改成 '  试试
匹配出来的结果一样

就是我发现,同样的一个正则规则,放在print里面和放在re.findall里面有差别

同时,照理说,双引号转义,单引号不转,但是单引号放在re.findall里面,也没有转义啊,大神

作者: crossin先生    时间: 2016-2-4 21:45
xqqxjnt1988 发表于 2016-2-4 14:02
crossing先生,请帮我看看这个问题啊,谢谢

#!/usr/bin/python

转不转义和是不是单引号双引号没关系。

正则里加r,是保证这个规则不转义,所以这个规则字符串是\b \S,它们应用到搜索,是去匹配对应的规则。
如果是要匹配\b或者\S这种字符本身,那这个规则要防止这些元字符的转义。所以得用r"\\b" r"\\S"

可能比较绕。建议自己把几种情况再多试试,体会一下

作者: crossin先生    时间: 2016-2-4 21:55
catherinemic 发表于 2016-2-2 14:46
Crossin老师,想问一下,既然r'\bhi'表示非转译的原始字符‘\bhi',但是为什么re.findall(r'\bhi', text)的 ...

我前面说的可能有点不对。如果一段话中有\bhi这个文字,你想匹配出来,规则需要写成
r"\\bhi"
以防止\b作为特殊元字符去匹配
作者: crossin先生    时间: 2016-2-4 22:05
catherinemic 发表于 2016-2-2 14:46
Crossin老师,想问一下,既然r'\bhi'表示非转译的原始字符‘\bhi',但是为什么re.findall(r'\bhi', text)的 ...

我前面说的可能有点不对。如果一段话中有\bhi这个文字,你想匹配出来,规则需要写成
r"\\bhi"
以防止\b作为特殊元字符去匹配
作者: catherinemic    时间: 2016-2-12 11:42
crossin先生 发表于 2016-2-4 22:05
我前面说的可能有点不对。如果一段话中有\bhi这个文字,你想匹配出来,规则需要写成
r"\\bhi"
以防止\b作 ...

嗯嗯,我明白了,\b在pyhon中本身有特殊含义,和在正则表达式中意义又不一样,所以需要做两层区分~~
作者: Kunz    时间: 2016-2-29 13:59
import re
text='site sea sue sweet see case sse ssee loses'
m=re.findall(r'\bs\S*?e\b',text)
if m:
    print(m)
else:
    print('not match')

作者: dekun    时间: 2016-6-11 10:14
import re
text = "site sea sue sweet see case sse ssee loses"
i = re.findall(r"s.*?e", text)
if i:
    print i
else:
    print 'not match'
   
作者: 红白姬    时间: 2017-1-31 10:20
  1. import re
  2. text = r"a\bc"
  3. m = re.findall(r"\\b",text)
  4. if m:
  5.     print m
  6. else:
  7.     print 'not match'
复制代码
C老师你好,
为什么这样输出的结果是["\\b"]而不是["\b"]?不是应该匹配出"\b"这个字符的吗?
================== RESTART: C:\Python27\新建文件夹\test0.py ==================
['\\b']
作者: crossin先生    时间: 2017-1-31 10:54
红白姬 发表于 2017-1-31 10:20
C老师你好,
为什么这样输出的结果是["\\b"]而不是["\b"]?不是应该匹配出"\b"这个字符的吗?
============ ...

正则的规则:
\b 表示匹配单词边界
\\ 表示匹配字符 \
\\b 表示匹配字符 \b

所以最后匹配出的结果是 \b,因为字符串转义,在字符串中的显示是 \\b(list中保持原始的字符状态)
如果你 print m[0],就看到输出是 \b
作者: 红白姬    时间: 2017-1-31 11:11
crossin先生 发表于 2017-1-31 10:54
正则的规则:
\b 表示匹配单词边界
\\ 表示匹配字符 \

懂了,谢谢老师
请问老师,我直接print "\b"
打印出的这个是什么字符啊?

QQ图片20170131111021.png (905 Bytes, 下载次数: 612)

QQ图片20170131111021.png


作者: crossin先生    时间: 2017-2-1 11:17
红白姬 发表于 2017-1-31 11:11
懂了,谢谢老师
请问老师,我直接print "\b"
打印出的这个是什么字符啊?

回退键
作者: nekonekobox    时间: 2017-2-4 22:30
  1. #-*- coding:utf-8 -*-
  2. import re
  3. text = "site sea sue sweet see case sse ssee loses"
  4. m = re.findall(r"\bs\S*e\b", text)
  5. if m:
  6.     print(m)
  7. else:
  8.     print('not match')
复制代码

作者: brahmagupta    时间: 2017-3-1 22:23
试着写了一下,r"\bs\S.?e\b"这个可以。不知道还有没有更简短的 表达式
作者: blueheart    时间: 2017-8-25 10:57
  1. import re

  2. text = "site sea sue sweet see case sse ssee loses"


  3. m = re.findall(r"\bs\S*?e\b",text)  #不包括空白字符

  4. if m:

  5.     print m

  6. else:

  7.     print 'not match'
复制代码
为什么要加r不转义?r是不转义字符串中的任何字符,保持它的原样.感觉不太对劲
作者: crossin先生    时间: 2017-8-26 13:04
blueheart 发表于 2017-8-25 10:57
为什么要加r不转义?r是不转义字符串中的任何字符,保持它的原样.感觉不太对劲 ...

r是为了字符串不转义,分清字符串本身和正则规则这是两个东西
字符串不转义,才能保证正则拿到 \b 这个规则
作者: wwyy4ever    时间: 2018-2-13 14:32
import re
text = "site sea sue sweet see case sse ssee loses"
m = re.findall(r"\bs\S*?e\b", text)
print m
作者: dreamwell    时间: 2019-1-4 09:09
“你若是暴力一点,也可以直接用“.”去匹配,看看会得到什么。”
坑啊,搞得我的电脑直接蓝屏。。。。。。
版主,解释一下什么原因啊。。。。。。
作者: crossin先生    时间: 2019-1-4 17:49
dreamwell 发表于 2019-1-4 09:09
“你若是暴力一点,也可以直接用“.”去匹配,看看会得到什么。”
坑啊,搞得我的电脑直接蓝屏。。。。。。 ...

这应该跟我无关……只是巧合吧

用 . 只是会把每一个字符都单独分开匹配出来




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