如何才能写出一个符合预期的正则?
随着爬虫日益普及,很多人开始捡起了正则,做一些简单的信息提取处理,越来越多的个性化正则表达式的需求,可还是有很多人不知道怎么下手,无法编写出一个强壮的正则,毕竟看起来和乱码差不多。
老顾这里用几个问答小伙伴的例子,来简单说一下,正则的写法。
不过,本文不讲述正则的基本支持,有需要补课的小伙伴,可以看老顾以前的文章:
《文盲的正则表达式入门》
《揭开正则表达式的神秘面纱》
《python 正则使用详解》
《文盲的正则表达式入门,实战篇》
老顾之前发了个实战篇,本意是有小伙伴可以提问,结果老顾高估了自己的人气,所以一直也没有小伙伴提问,所以老顾干脆,从新从另外一个角度,来讲述一下怎么写正则表达式好了。希望大家看完本文,能够自己写出强壮的正则来。
问答地址:https://ask.csdn.net/questions/7919433?spm=1005.2025.3001.5141
预期结果是abcd,为什么运行结果是ad啊
String s = "abbbbccccdddddddddd";
String s1 = s.replaceAll("((.)\\2)+", "$2");
问题描述:有字符串“abbbbccccdddddddddd”,期望所有连续重复的字符只保留一个
一个简单的问题,我们只需要把问题描述改成正则描述即可
判断连续的字符,需要用到分组,即将任意字符作为一个分组,然后后边跟随该分组引用
(.)(?:\1)*
这个正则片段中,第一个括号表示分组,第二个括号,老顾加上了?: 修饰,表示不参与分组,\1 表示引用第一个分组,然后对引用分组的结果加上一个长度修饰,老顾用的是*,表示0到多个,然后,因为默认长度模式是贪婪模式,所以,这个正则就算完成了,然后,在替换部分也加上引用就可以了。
python 测试
import re
print(re.sub(r'(.)(?:\1)*','\\1','abbbbccccdddddddddd'))
abcd
print(re.sub(r'(.)(?:\1)*','\\1','aabaacadaadde'))
abacadade
javascript 测试
'abbbbccccdddddddddd'.replace(/(.)(?:\1)*/gi,'$1')
'abcd'
'aabaacadaadde'.replace(/(.)(?:\1)*/gi,'$1')
'abacadade'
题主在问答中,给出了自己的正则
((.)\2)+
这里需要注意模式问题哦,这个正则解读如下
字符串数据:abbbbccccdddddddddd
正则表达式:((.)\2)+
首先是 (.) 表示任意字符,并放入分组
然后是(.)\2 ,因为外层还有一个分组,所以内层分组的分组序号是2,这里表示引用前边的这个(.) 的匹配结果,也就是连续字符,比如 bb,比如 cc
再然后是对连续字符的分组 ((.)\2)+ 并有长度修饰,注意,长度修饰是贪婪模式哦,所以这个正则匹配到的内容是
bbbbccccdddddddddd,所以在使用替换的时候,这么一大串,会当做一个匹配来处理
最后替换引用的 $2,也就是第二个分组内容,是在上述匹配时,最后一个符合的内容
bb bb cc cc dd dd dd dd dd,那么最后一个符合分组的匹配是 dd,所以第二个引用的结果就是字母 d
所以破案了,题主的结果为什么是 ad
问答地址:https://ask.csdn.net/questions/7916098?spm=1005.2025.3001.5141
一个金额的正则校验,整数部分最多16位,以千分位展示,小数点后保留两位小数且第三位不可输入
看题主的意思,应该是一个数据验证,校验输入的数据是否符合金额的千分格式
这个正则稍微复杂了一点,他的需求可以拆分为几个小的描述
1、整数部分最多16位
2、整数部分以千分位展示
3、小数点后保留两位小数
那么,逻辑就出来了,小数点后保留两位是必须得,整数部分长度是最大16位,然后每三位加一个逗号的样子,也就是21位
所以第一个片段,我们先验证字符串长度
^(?=[^\.]{1,21}(?=\.))
这个片段是什么意思呢?
^ 表示从字符串开头开始匹配
(?=) 表示右断言,或者说预搜索,表示从当前位置,后边的内容应该是这个样子的
[^\.]{1,21} 表示除了小数点之外,其他任意字符,长度在1到21之间
(?=\.) 后边又跟了一个右断言,表示上述长度的字符串后,必须跟一个小数点的样子
那么小数点之前的长度验证完成了,然后我们需要验证是否是千分位格式,这个时候就不用断言了
\d{1,3}(,\d{3})*\.\d{2}$
这个片段的意思就是
\d{1,3} 必须是1到3个数字开头
(,\d{3})* 后边跟上多个以逗号开头的三位数
\. 然后是必须有的小数点
\d{2} 然后是一个必须有的小数点后两位数
$ 最后是字符串结束
那么完整的正则就是
^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$
python 测试
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100.00'))
<re.Match object; span=(0, 6), match='100.00'>
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','100.000'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1000.00'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1,000.00'))
<re.Match object; span=(0, 8), match='1,000.00'>
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','10,000,000,000,000,000.00'))
None
print(re.search(r'^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$','1,000,000,000,000,000.00'))
<re.Match object; span=(0, 24), match='1,000,000,000,000,000.00'>
javascript 测试
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('100.000')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1000.000')
false
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1,000.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('1,000,000,000,000,000.00')
true
/^(?=[^\.]{1,21}(?=\.))\d{1,3}(,\d{3})*\.\d{2}$/gi.test('10,000,000,000,000,000.00')
false
问答地址:https://ask.csdn.net/questions/7916062?spm=1005.2025.3001.5141
#java正则 #正则表达式分割#java断言
请教,想要根据 ( ) 外的 | 分割字符串,正则表达是该如何匹配呢?
例如:
%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% 分割后应为 如果是 \( \) 则不不认为是括号
%这个一个测试2
4\)11
(0jh|96)78
8\)k
字符串%
额,这个更加复杂了一点,比千分位验证的难不少。咱们先捋捋需求啊
1、对竖线前后内容进行分割
2、如果竖线在括号内则不进行分割
3、如果括号是被转义的,则不认为是括号
其实,这个需求读下来,还有一个隐藏的条件,就是如果括号不成对的时候,是很难处理的,好在题主没有这个说明,咱就当括号是严格匹配的。
这次,就不能一口气实现了,咱们分阶段实现好了
\|
print('\n'.join(re.split(r'\|','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2
4\)11
(0jh
96)78
8\)k
字符串%
先按照最基本的需求,以竖线分割字符串
然后,我们将竖线限定为括号外的竖线,括号内的忽略
\|(?=[^\)]*(?:$|\|))
print('\n'.join(re.split(r'\|(?=[^\)]*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2|4\)11
(0jh|96)78|8\)k
字符串%
我们追加了一个右断言
(?=[^\)]*(?:$|\())
用来限定,竖线后边没有右括号,直到碰到另一个竖线或者字符串结束
[^\)]* 非右括号内容
(?:$|\|) 竖线或者字符串结束
然后,我们需要对转义的括号进行一下处理
\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))
print('\n'.join(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% ')))
%这个一个测试2
4\)11
(0jh|96)78
8\)k
字符串%
这次,我们是对原来的 [^\)] 部分进行了一些调整,指定 \\\( 和 \\\) 可以被匹配
这个时候,这个正则就符合题主的要求了
python 测试
print(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','%这个一个测试2|4\)11|(0jh|96)78|8\)k|字符串% '))
['%这个一个测试2', '4\\)11', '(0jh|96)78', '8\\)k', '字符串% ']
print(re.split(r'\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))','用|分割所有内容|(括号里的|被忽视)|如果括号\\(转义|会忽略转义\\)的括号'))
['用', '分割所有内容', '(括号里的|被忽视)', '如果括号\\(转义', '会忽略转义\\)的括号']
javascript 测试
'%这个一个测试2|4\\)11|(0jh|96)78|8\\)k|字符串% '.split(/\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))/gi)
(5) ['%这个一个测试2', '4\)11', '(0jh|96)78', '8\)k', '字符串% ']
'用|分割所有内容|(括号里的|被忽视)|如果括号\\(转义|会忽略转义\\)的括号'.split(/\|(?=(?:[^\)]|\\\(|\\\))*(?:$|\|))/gi)
(5) ['用', '分割所有内容', '(括号里的|被忽视)', '如果括号\(转义', '会忽略转义\)的括号']
问答地址:https://ask.csdn.net/questions/7907410/54127882?spm=1001.2014.3001.5501
正则表达式
匹配汉字中ABB类型的词组
import re
text = input()
words = re.findall(r'((.)(.)\3)',text)
print(words)
这个正则表达式能匹配ABB但是也能匹配三个相同的汉字,有没有办法让第一个汉字与第二个汉字不同
哦吼,和第一个示例差不多的内容,不过要求前边还有一个不同的字符
来描述一下需求,很简单的
需要abb形式的内容,且a与b不得相同
那么我们已经学会分组,也学会断言了,实现起来还是很简单的
(.)(?!\1)(.)\2
多简单的实现,分组1后边不能跟和分组1相同的内容,分组2后边跟分组2相同的内容,这不就是 abb 形式了么
python 测试
re.findall(r'((.)(?!\2)(.)\3)','add and all food zzz 宋甜甜,范若若,戚戚惨惨切切')
Out[24]:
[('add', 'a', 'd'),
('all', 'a', 'l'),
('foo', 'f', 'o'),
(' zz', ' ', 'z'),
('宋甜甜', '宋', '甜'),
('范若若', '范', '若'),
(',戚戚', ',', '戚'),
('惨切切', '惨', '切')]
javascript 测试
'add and all food zzz 宋甜甜,范若若,戚戚惨惨切切'.match(/((.)(?!\2)(.)\3)/gi)
(8) ['add', 'all', 'foo', ' zz', '宋甜甜', '范若若', ',戚戚', '惨切切']
大体实现了题主的需求了,一些 空格标点之类的也参与了进来,无伤大雅,自己把点修改成指定的字符集即可
在这个示例里,老顾自己写了个字符串,戚戚惨惨切切,那么,如果要匹配 abb 形式,其实应该是有两个结果:戚惨惨,惨切切。
而正常的正则在匹配时,每个字符只能参与一次匹配,如何才能让字符参与多次匹配呢?
其实应该有小伙伴反应过来了,使用右断言啊!右断言又叫预搜索可不是白叫的哦。
那么,最后的正则也就可以想到了,用预搜索来实现 abb 组合的检索
re.findall(r'(?=((.)(?!\2)(.)\3))','add and all food zzz 宋甜甜,范若若,戚戚惨惨切切')
Out[25]:
[('add', 'a', 'd'),
('all', 'a', 'l'),
('foo', 'f', 'o'),
(' zz', ' ', 'z'),
('宋甜甜', '宋', '甜'),
('范若若', '范', '若'),
(',戚戚', ',', '戚'),
('戚惨惨', '戚', '惨'),
('惨切切', '惨', '切')]
但是,这个正则是基于 python 正则匹配的特性,即:如果有分组,则所有分组结果以元组形式返回
在 c# 等支持分组的语言环境,这么写也没有问题,大不了去取第一个分组的值罢了,但是,在 js 这么写就不可行了,因为他不会返回分组的内容,而是匹配到位置了,返回一个位置信息,没有内容了!
那么 js 的正则就需要做一个大改动了。
Array.from('add and all food zzz 宋甜甜,范若若,戚戚惨惨切切'.matchAll(/(?=((.)(?!\2)(.)\3))(?=.{3})/gi)).map(x => x[1])
(9) ['add', 'all', 'foo', ' zz', '宋甜甜', '范若若', ',戚戚', '戚惨惨', '惨切切']
这里,我们用到了 es6 的一些新特性,来辅助我们获取第一个分组的内容,好在也是可以做到的
现在又讲解了几个例子,结合老顾之前的几篇入门文章,相信小伙伴们已经对正则的编写有了新的体会了,那么,就放手去练习吧,只有多练多用,才会真正的掌握这些技巧。
纸上得来终觉浅,方知此事须躬行。

我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>