正则表达式,用于在一大堆数据中查找信息,学习后有利于爬虫信息抓取。
“. ^ $ * + ? { } [ ] \ | ( )”是元字符(关键字),如要匹配原字符则需加“\”,如“\[”“\\”。为避免与转义符(\n、\b)冲突,可在字符串前加r,即 r"" 或 r'' 。
字符:
“\d”表示数字
“\D”表示非数字的字符
“\s”表示空白字符,相当于[ \t\n\r\f\v]
“\S”相当于[^ \t\n\r\f\v]
“\w”表示数字或字母
“\W”表示非数字和字母的字符
“.”表示除换行符'\n'外的所有字符,DOTALL模式下可匹配任何字符(包括'\n')
“[]”整体为一个字符,其中的内容表示"或者"关系,同时元字符全部失效。如:[12]表示'1'或'2',[a-z]表示小写字母(包括扩展拉丁字母如 'é'),[A-Za-z]表示所有字母,而[^a]表示除'a'以外的所有字符,[a^]表示'a'或'^'。由于元字符失效,从而可以 '[\n]' 的方式表示回车符等转义符,但复杂情况下仍推荐使用 r""。
以下字符都不代表实际字符,即所谓零宽度,称为断言:
“^”指示行的开头,不代表实际字符,如MULTILINE模式下以“^a”去匹配“b\nab”则span=(2, 3)。若不是MULTILINE,则仅指示字符串开头。
“$”指示行的末尾。同样需要MULTILINE
“\A”指示字符串的开头
“\Z”指示字符串的末尾
“\b”指示词边界,即每个单词的开头和结尾,单词结构中可包括数字和字母,其他字符如空格逗号可以将其分割为一个个单词。可以指示字符串开头。可能与退格符'\b'冲突,加r或使用'\\b'。
“|”表示或者,优先级比普通字符还低,如“phone|tele”表示"phone"或"tele"
而“()”可控制“|”的范围,如“the (phone|tele)”
重复:
“*”表示前一个字符重复0~+inf次
“+”表示前一个字符重复1~+inf次
“?”表示前一个字符重复0或1次,可有可无
“{m}”表示前一个字符重复m次
“{a,b}”表示前一个字符重复a~b次,同时“{,b}”表示0~b,“{a,}”表示a~+inf次。注意大括号中不可包含空格,如“{a, b}”是错误的,应为“{a,b}”。
以上符号默认均为贪婪模式,即匹配尽可能多的字符。如果需匹配尽可能少的字符,可在其后加上“?”符号,如“a*?”为非贪婪模式。
“()”可使重复符号作用于其括住的全部字符上,如“(br)*”指'br'重复0~+inf次
【re模块】
基本方法:
“p = re.compile(r'ab*')”编译一个匹配器(正则),r'ab*'为匹配规则的表达式(模式)
“m = p.match('abbcabd')”在'abbcabd'中从第一个字符开始匹配,结果保存在match对象中并返回
“m = p.search('abbcabd')”在'abbcabd'中不断向后查找,只返回第一个最先匹配到的内容
“listAll = p.findall('abbcabd')”在'abbcabd'中不断向后查找所有能匹配的内容,并将其以列表的方式返回
“iterAll = p.finditer('abbcabd')”上一种方式的迭代器版本,迭代时才查找并返回内容
“s = m.group()”或“s = m.group(0)”获得匹配的内容
“s = m.start()”获得匹配内容在字符串中的起始索引值,指向匹配内容的第一个字符
“s = m.end()”获得匹配内容在字符串中的终止索引值,指向匹配内容最后一个字符的后一个字符
“s = m.span()”获得匹配内容在字符串中的范围,元组方式返回,范围为左包含而右不包含的
“print(m)”输出匹配的范围和内容
分组:
在正则表达式中把需要的信息用小括号“()”括起来,即可获得它们,称为分组。如:
“p = re.compile(r'\w(\w)(\w+)')”
“m = p.match('This is Python')”
之后“m.group(1)”可返回第一个分组的内容,即'h'
“m.group(2)”可返回第二个分组的内容,即'is'
以此类推
而“m.group()”或“m.group(0)”依然返回匹配到的所有内容,即 'This'
“m.groups()”可将所有分组内容以元组的方式返回,即('h', 'is')
分组编号从左到右,由内而外。如以r'\w((\w)\w+)'匹配'This is Python'则第一个分组内容为 'his',第二个为 'h',groups()得 ('his', 'h')。
“\1”可指代前面第一个分组匹配到的内容,表示“\1”这里必须要再次出现此内容,可用于检测双字(叠词)。如:
p = re.compile(r'\b(\w+)\s+\1\b')
print(p.search('Paris in the the spring').group())
得:'the the'。
注意:分组后“findall”和“finditer”只返回分组的内容,若有多个分组则将每次匹配到的各分组内容以元组的方式存储在列表中。
更多分组:
“(?: ... )”中 ' ... ' 处输入的表达式匹配后不会被groups()捕获。可用于不重要信息的重复如 r'(?:the\s?)*'。称为非捕获组
“(?P<gr>...)”可将此分组命名为 'gr' ,之后通过“group('gr')”可获得此分组的内容。称为命名组
同时“(?P=gr)”可指代前面分组名为 'gr' 匹配到的内容,表示“(?P=gr)”这里必须要再次出现此内容。
以上两种表达式的“P”指Python特有。
“m.groupdict()”可返回所有被命名的分组内容,分组名为键(key),分组内容为值(value)
“(?#…)”为注释,可被忽略
“(?(id/name)a|b)”指如果编号为 'id' 的分组或名称为 'name' 的命名组存在,则匹配a表达式,否则匹配b表达式
前向断言:
“(?=…)”指此处应出现表达式 '...' 所描述的内容,如无则此次匹配失败。匹配成功后,其自身不计入匹配内容,原因是其自身不代表实际字符,即零宽度。这被称为前向肯定断言。如字符串 "What's that?",若以 r"What's(?=\sth)" 匹配之则得 "What's",若以 r"What's(?=\sth)\s\w+[?]$" 匹配之则得 "What's that?"。
“(?!…)”与上一种相反,指此处不应出现表达式 '...' 所描述的内容,如出现则此次匹配失败。这被称为前向否定断言。可用于排除某种文件后缀,如 r'.*[.](?!bat$)[^.]*$' 只可匹配后缀为"bat"
后向断言:
“(?<=…)”为后向肯定断言,与 '(?=...)' 作用基本相同,不计入匹配内容,但其自身可以代表实际字符。如字符串 "It's spam-egg",若以 r"(?<=-)\w+" search之则仍得 "egg"。“(?<=…)”中不可添加重复(\s*、a{1, 4}),但可添加其他内容如 '|'
“(?<!…)”为后向否定断言,与上一种相反,同样不可添加重复
标志:
可以在re.compile()中增加匹配标志的参数,相当于对匹配方式进行设置。标志可以叠加,在其之间需加上 '|' 按位与运算符,如:“p.compile(r'ab*, re.M|re.I)”
“re.M”设置MULTILINE模式(多行匹配模式),使 '^' 指示行的开头, '$' 指示行的末尾。也可写为“re.MULTILINE”
“re.I”设置IGNORECASE模式,忽略大小写,即大写既可匹配大写也可匹配小写,小写既可匹配小写也可匹配大写。也可写为“re.IGNORECASE”
“re.L”设置LOCALE模式,方便处理本地所使用的拉丁语言。比如 'é' 'ñ' 'ç' 对于西班牙语而言只有 'é' 'ñ' 是字母,但对于法语而言则只有 'é' 'ç' 是字母。未设置re.L时,Python3默认进行 Unicode 匹配,即将 'é' 'ñ' 'ç' 都识别为字母。设置后,则据地区而定。主要影响 '\w' '\W' '\b' '\B' 和大小写忽略(re.I)。也可写为“re.LOCALE”
“re.S”设置DOTALL模式,使 '.' 可匹配任何字符,包括 '\n'。也可写为“re.DOTALL”
“re.A”设置ASCII模式,使默认的 Unicode 匹配变为 ASCII 匹配,影响 '\w' '\W' '\b' '\B' '\s' '\S' 的工作。也可写为“re.ASCI”
“re.U”设置UNICODE模式,与上一个模式相反,也可写为“re.UNICODE”
“re.X”设置VERBOSE模式,可使正则表达式更易读。设置re.X后,表达式中所有空格都将被忽略,并且允许加入注释,指示各部分的含义,也可写为“re.VERBOSE”,如:
1 charref = re.compile(r"""
2 &[#] # Start of a numeric entity reference
3 (
4 0[0-7]+ # Octal form
5 | [0-9]+ # Decimal form
6 | x[0-9a-fA-F]+ # Hexadecimal form
7 )
8 ; # Trailing semicolon
9 """, re.VERBOSE)
若未设置re.X则写为:
1 charref = re.compile("&#(0[0-7]+"
2 "|[0-9]+"
3 "|x[0-9a-fA-F]+);")
设置后空格需以 r'\ ' 表示。
模块级函数:
可以不编译匹配器(正则)而直接使用相应函数匹配内容,如:
“m = match(r'ab*', 'abbcabd', re.M)”
“m = search(r'ab*', 'abbcabd', re.M)”
“listAll = findall(r'ab*', 'abbcabd', re.M)”
“iterAll = finditer(r'ab*', 'abbcabd', re.M)”
都将表达式放在第一个参数、字符串在第二个参数、标志在第三个参数即可。
正则表达式用于处理字符串的re函数:
“re.split()”可以以正则表达式匹配的内容为分割符,分割字符串。所匹配的字符将被丢弃。
如:
“p = re.compile(r'\W+')”
“listS = p.split("This is short and sweet.")”
结果为:['This', 'is', 'short', 'and', 'sweet', '']
可指定其最大分割次数,如:
“p.split("This is short and sweet.", maxsplit=2)”指split最多分割2两次,
得:['This', 'is', 'short and sweet.']
也可写为“p.split("This is short and sweet.", 2)”
若正则中有捕获分组,则还将返回捕获分组的内容,如:
“p2 = re.compile(r'(\W+)')”
“listS2 = p2.split("This is short and sweet.")”
结果为:['This', ' ', 'is', ' ', 'short', ' ', 'and', ' ', 'sweet', '.', '']
“re.sub()”可将正则在字符串中匹配到的内容替换为另一个内容。
如:
“p = re.compile('(blue|white|red)')”
“s = p.sub('colour', 'blue socks and red shoes')”
结果为:'colour socks and colour shoes'
sub()同样可指定最大替换次数,如:
“p.sub('colour', 'blue socks and red shoes', count=1)”指sub最多替换1次,
得:'colour socks and red shoes'
也可写为“p.sub('colour', 'blue socks and red shoes', 1)”
所替换成的另一个内容中可引用匹配内容中的分组内容,可写为 '\1' 或 '\g<1>' ,表示引用第一个分组。对于命名组 '(?P<name>...)' 还可写为 '\g<name>' ,如:
“p = re.compile('section{ (?P<name> [^}]* ) }', re.X)”
“p.sub(r'subsection{\1}','section{First}')”
“p.sub(r'subsection{\g<1>}','section{First}')”
“p.sub(r'subsection{\g<name>}','section{First}')”
结果均为:'subsection{First}'
还可为sub()传入一个函数,sub()会将匹配到的每一个内容以match对象的方式,传入函数中,然后将匹配的内容替换为函数的返回值。如:
“p = re.compile(r'\d+')”
“p.sub(func, 'Call 65490 for printing, 49152 for user code.')”
可依次将匹配到的 '65490'、'49152' 作为 match 对象,传入 func 函数。
若 func = lambda m: hex(int(m.group())) ,则得:
'Call 0xffd2 for printing, 0xc000 for user code.'
此方法可将字符串中的各个整数替换为16进制数
“subn()”的用法与sub()完全相同,但还会返回替换次数,如:
“p = re.compile('(blue|white|red)')”
“s = p.subn('colour', 'blue socks and red shoes')”
结果为:('colour socks and colour shoes', 2)
更多方法/函数:
“p.fullmatch()”或“re.fullmatch()”用法与match()一样,但要求正则与字符串必须从头到尾完全匹配,否则返回None。相当于在正则末尾加了一个 '\Z'
“p.flags()”获得匹配器p的所有标志,返回值可直接传入compile()
“p.pattern()”获得匹配器p的正则,以字符串形式返回
“re.escape()”可在字符串中的所有元字符前加 '\' ,避免正则转义,如“print(re.escape('https://www.python.org'))”得 "https://www\.python\.org"
“re.purge()”可清除正则表达式的缓存
“(?...)”也可用于设置标记,放在正则前。如 '(?aiLmsux)^asd&' 可为 '^asd&' 开启 re.A ~ re.X 所有标志。实测效果不太理想。
【例题】
1、 找出一个字符串中所有的数字,其中整数用千分位形式表示,即从个位数起,每3位之间加一个逗号,比如1,000,000,小数用定点十进制表示,并且小数点之前至少有一位数字(比如0.618中的0不可省略)。
如:'1,234.56-234.56=1,000'
返回:['1,234.56', '234.56', '1,000']
解:
1 s = r'1,234.56-234.56=1,000'
2
3 p = re.compile(r"(\d{1,3}(?:,\d{3})*(?:\.\d+)?)")
4 L = p.findall(s)
5 print(L)
参考:
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
我一直致力于让我们的Rails2.3.8应用程序在JRuby下正确运行。一切正常,直到我启用config.threadsafe!以实现JRuby提供的并发性。这导致lib/中的模块和类不再自动加载。使用config.threadsafe!启用:$rubyscript/runner-eproduction'pSim::Sim200Provisioner'/Users/amchale/.rvm/gems/jruby-1.5.1@web-services/gems/activesupport-2.3.8/lib/active_support/dependencies.rb:105:in`co
这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。