我建议尝试解决Callum Macrae的10个正则表达式测试。 与我之前对挑战的分析不同,坦率地说,没有简单甚至普通的任务。 正如他们所说-只有正则表达式,只有铁杆。
由于挑战非常复杂,因此没有必要像我一样遵守所有规则,任何通过测试的人都是100%-意味着您是一名超级专业人士。 欢迎光临!
是的,我知道,这个挑战已经发布过一次。 但是帖子的作者没有提出可行的解决方案,并且在评论中人们无法解决另外4个问题,甚至更多时候甚至不了解任务的含义以及他们希望从中获得什么。
因此,我再次发布它,并提供详细的翻译,解释和所有依赖的包子。
任务1-突出显示重复的单词
http://callumacrae.imtqy.com/regex-tuesday/challenge1.html
有一组句子,此句子中可能有重复的单词。 有必要突出显示重复的单词。
一个例子:
This is is a test
在这种情况下,单词“是”被重复两次,并以粗体突出显示:
This is <strong>is</strong> a test
提示必须找到单词的重复,并且单词之间用空格隔开,因此-需要空格字符。 在正则表达式中,从技术上讲,仅可以通过反向链接找到重复。
解决方案表达方式:
/\b([\w']+)\s(\1)\b/gi
更换:
$1 <strong>$2</strong>
解析解决方案- “ \ b”-应该从单词边界开始
- “([[w w'] +)”-任意数量的字母,数字和撇号(您也可以用空格以外的任何符号来解决它),并确保将其捕获在一个组中,因为 接下来,您需要查找该组的重复项。
- “ \ s(\ 1)”-因为我们知道重复出现在空格之后,所以我们在空格处放置“ \ s”,然后写成在此之后必须捕获先前捕获的第一组“(\ 1)”的重复。
- “ \ b”-重复必须以单词边界结束,否则我们可能会捕获仅单词的一部分。
任务2-灰度
http://callumacrae.imtqy.com/regex-tuesday/challenge2.html
有不同格式的颜色代码,任务是查找所有灰色阴影。
有效代码示例:
#eEe #6F6F6F rgb(2.5, 2.5,2.5) hsl(0, 10%, 100%)
无效代码示例:
#eEf #11111e rgb(1.5%, 1.5%, 1.6%) hsl(20, 20%, 20%)
代码说明此任务中最重要的问题是什么是灰色。
根据维基百科,灰色为:
通过将RGB颜色模型的三种原色-红色,绿色和蓝色以相同的浓度组合在一起而获得的许多颜色。
以#开头的代码是十六进制格式,有两种形式。 缩写,三个字符(#rgb),完整,六个字符$ rrggbb。 其中r,g,b是三个原色。
rgb(r,g,b)码完全相同,它们仅以0到255之间的数字书写。
hsl格式要复杂一些,这里的数字表示色调,饱和度和亮度。 例如,要了解在什么条件下以相等的比例获得三种原色,可以使用此可视化编辑器进行操作。
提示对于缩写的十六进制,正确的出现是所有三个字符的重复,例如#aaa。 对于完整的十六进制,请重复两个字符,例如#efefef。 对于数字rgb,请重复数字,例如rgb(2,2,2)。 了解hsl格式要稍微复杂一些,但是仍然了解上述内容,您可以理解,此处的灰色是色调为0或饱和度为0或100时的颜色。
因此,与上一个任务一样,您需要使用反向链接。 由于您需要考虑许多不同的选项,包括那些写得不正确的选项,因此所得的正则表达式将很大(这是正常的)。
解决方案 /^(?:#(\w)\1\1|#(\w{2})\2\2|rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\)|rgba\(([\d.]+%?),[0 ]*\4,[0 ]*\4,[^)]+\)|hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\))$/i
解析解决方案为每种颜色编写一个单独的皱褶,我们将分别对其进行分析:
#(\w)\1\1
- “(\ w)”在组中包含一个字符。
- “ \ 1 \ 1”-并指出应重复2次。
对于两个字符,同一件事-我不再重复。
rgb\(((?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])%?(?:\.\d+)?),[ ]?[0]*\3,[ ]?[0]*\3\)
我想写“ rgba?”,但是当在rgb()中指定第四个参数时,可能会出现这种情况,因此rgb和rgba需要分别描述:
- “ \ d {1,2} | 1 \ d {2} | 2 [0-4] \ d | 25 [0-5]”-范围是从0到255。我将不对其进行详细分析,您可以在此处查看任务5。
- “(?:\。\ d +)?” -一个未分配号码的可选组。 一个点和一个点之后的数字都是可能的(这适用于非整数)。
- “,[]?[0] * \ 3”-强制逗号,后跟0或1空格,0或许多零,之后应重复先前捕获的组的值。
在rgba()中-相同,但是需要4个参数。
hsla?\([\d.]+,[ ]*(0%[^)]+|[\d.]+%,[ ]*(0|100)%[^\)]*)\)
在这里,您还需要以一种很好的方式将hsl和hsla分开,但是测试用例中没有这种情况,因此我们将写一些“ hsla?”。
- “ [\ d。] +,[] *”-首先是必需的数字“ [\ d。] +”(不包括整数),带有强制逗号和可选空格“ [] *”。
- “((0%[^)] + | [\ d。] +%,[] *(0 | 100)%[^)] *”-然后可能有两个选择:1)首先出现0%,然后是0%除方括号[^)]以外的其他字符+ 2)任何带有强制百分号和逗号“ [\ d。] +%”的数字,然后是0%或100%“((0 | 100)%”)。
任务3-查找日期
http://callumacrae.imtqy.com/regex-tuesday/challenge3.html
有一个日期列表,从这些日期中可以找到日期从1000年到2012年(包括YYYY / MM / DD HH:MM(:SS))。 每个字母都是必填数字,而不是方括号。
例子
2001/09/30 23:59:11
提示“ [0-9]”不是数字范围,它是表示0-9之间的单个字符有效的表达式。 在正则表达式中,没有大数的范围,但是从这么小的片段中,您可以制作覆盖所需范围的正则表达式。 示例:“ 1 [0-9]”-范围从10到19。
解决方案 /^(1[\d]{3}|200\d|201[0-2])\/(0[1-9]|1[0-2])\/(0[1-9]|1[0-9]|2[0-9]|3[0-2])\s(0[0-9]|1[0-9]|2[0-3]):([0-5][\d])(:([0-5][\d]))?$/
解析解决方案- 有效年份为“((1 [\ d] {3} | 200 \ d | 201 [0-2])””,其中顺序从1000到1999,从2000到2009,从2010到2012。
- 月“((0 [1-9] | 1 [0-2])””。 从01到09和10到12。
- 天“(0 [1-9] | 1 [0-9] | 2 [0-9] | 3 [0-2])”。 从01到09,从10到19,从20到29和从30到32。
- 小时“(0 [0-9] | 1 [0-9] | 2 [0-3])”。 从00到09和10到19,从20到23。
- 分钟“([[0-5] [\ d])”。 00至59
- (:([[0-5] [\ d])))? -可选秒,从00到59。
任务4-斜体
http://callumacrae.imtqy.com/regex-tuesday/challenge4.html
有一个带有MarkDown标记的文本(就像在Habré上一样)。 您必须编写一个正则表达式,用<em>标记替换星号之间的单词。
例子
*This text is italic.* -> <em>This text is italic.</em>
提示您需要在之前和之后没有其他星号的地方找到一个星号。 只向前看,向前和向后看(最简单,但没有跨浏览器)。
解决方案表达方式:
/(^|[^*])\*([^*].*?[^*]|[^*])\*((?!\*)|$)/g
更换:
$1<em>$2</em>
解析解决方案- “(^ | [^ *])”-我们从行首开始,或者从星号以外的任何字符开始。 该小组需要捕获此符号并将其放在<em>标记之前。
- ((?!*)| $)-我们将以该行的结尾或除星号之外的任何字符结尾,因为在这里偷看-不会捕获空格。
- “([[^ *]。*?[^ *] | [^ *])””-中间有“ [^ *]。*?[^ *]”任何不应该以星号和表达式开头和结尾的文本或“ | [^ *]”只是为了考虑标记内的单个字符(无需通过测试)。
http://callumacrae.imtqy.com/regex-tuesday/challenge5.html
从数字列表中,仅选择格式正确的数字。 从右到左写数字,通常分为三个数字,这是公认的。
正确记录数字的示例:
1,024 8,205,500.4672 10.444444444444 30 000,7302
提示重要的是要考虑数字是完全从右到左书写的,而不是相反。 这意味着一个数字可以以1-3个数字开头,然后一个组中只能有三个数字。 在非整数部分,可以有任意数量的数字(或根本没有数字)。 请注意,组的分隔符可以是逗号或空格,整数和非整数部分的分隔符可以是逗号或句点。
解决方案表达方式:
/^\d{1,3}([ ,]\d{3})*([.,]\d+)?$/
解析解决方案- “ ^ \ d {1,3}”-1到3位数字的开头。
- “([[,] \ d {3})*”-进一步是一个分隔符和一组3个数字,星号表示我们的格式可以出现0次或多次。
- “([。,] \ d +)?$”-最后是一个带分隔符和数字的组,问号是一个量词,表示不存在非整数部分不是前提条件。
任务6-IP地址
http://callumacrae.imtqy.com/regex-tuesday/challenge6.html
从各种格式的IP地址列表中,找到有效的IP地址。 也许是最艰巨的任务。 没有那么复杂,多少沉闷。
有效IP地址条目的示例和说明:
- 192.0.2.235-带句点的十进制。
- 0300.0000.0002.0353-带有点的八进制。
- 0xC0.0x00.0x02.0xEB-带点的十六进制。
- 0xC00002EC-十六进制。
- 287454020-十进制。
- 030000001353-八进制。
混合使用不同格式是不好的。 尤其是数字。 带有点的ip地址格式可以混合,例如-0xFF.255.0377.0x12,这一事实使情况更加复杂。 我个人认为这是一个不好的做法,但是根据测试,这种选择是可能的,因此应将其考虑在内。
提示- 192.0.2.235-带句点的十进制。 点之间的通用符号可以表示为1到3位(0到255之间的值)。
- 0300.0000.0002.0353-带有点的八进制。 点之间的4位数字,值从0到7。
- 0xC0.0x00.0x02.0xEB-带点的十六进制。 点之间的四个字符。 前导“ 0x”,然后是两个字符(按数字或从“ a”到“ f”)。
- 0xC00002EC-十六进制。 前导“ 0x”,然后是8个字符(数字值或从“ a”到“ f”)。
- 287454020-十进制。 范围从0到4294967295的任何数字。
- 030000001353-八进制。 前导0。数字从0到7。范围从0到07777777777777。
正则表达式会很棒。
解决方案 /^((((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4}))\.){3}(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])|(0x[\da-f]{2})|([0-7]{4})))|(0x[\da-f]{8})|(0([0-7]{1,11}))|(2874540[2-8][0-9]|28745409[0-9]|287454[1-9][0-9]{2}|28745[5-9][0-9]{3}|2874[6-9][0-9]{4}|287[5-9][0-9]{5}|28[89][0-9]{6}|29[0-9]{7}|[3-9][0-9]{8}|[1-3][0-9]{9}|4[01][0-9]{8}|42[0-8][0-9]{7}|429[0-3][0-9]{6}|4294[0-8][0-9]{5}|42949[0-5][0-9]{4}|429496[0-6][0-9]{3}|4294967[01][0-9]{2}|42949672[0-8][0-9]|429496729[0-5]))$/i
解析解决方案对于带点的ip地址,可以进行混合,因此我们通过“ |”编写选项 通过这样的模式:(((十进制|十六进制|八进制)。){3}(十进制|十六进制|八进制)。
- “((\ d | [1-9] \ d | 1 \ d \ d | 2 [0-4] \ d | 25 [0-5])”-带有记录点的小数。
- “(0x [\ da-f] {2})”-带有记录点的十六进制。
- “([[0-7] {4})”-带有记录点的八进制。
和其他记录格式:
- “(0x [\ da-f] {8})”-十六进制表示法。
- “((2874540 [2-8] [0-9] | 28745409 [0-9] | 287454 [1-9] [0-9] {2} | 28745 [5-9] [0-9] {3} | 2874 [6-9] [0-9] {4} | 287 [5-9] [0-9] {5} | 28 [89] [0-9] {6} | 29 [0-9] {7} | [3-9] [0-9] {8} | [1-3] [0-9] {9} | 4 [01] [0-9] {8} | 42 [0-8 ] [0-9] {7} | 429 [0-3] [0-9] {6} | 4294 [0-8] [0-9] {5} | 42949 [0-5] [0-9 ] {4} | 429496 [0-6] [0-9] {3} | 4294967 [01] [0-9] {2} | 42949672 [0-8] [0-9] | 429496729 [0-5 ])“-代表十进制符号。 在这里,我必须承认,为了简短起见,我作弊,只在测试范围内包含十进制IP地址。 有益的是,在这里您需要考虑0到4294967295之间的任何数字。手动编写此代码不是一项值得感谢的任务,因此我们使用它 。
- (0([0-7] {1,11}))-八进制表示法。
任务7-网址
http://callumacrae.imtqy.com/regex-tuesday/challenge7.html
从网址列表中找到有效的网址。
有效地址示例:
http://ab https://example.com/ http://test.this-test.com/ http://1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa
提示该地址必须以http://或https://开头,并以斜杠,字母(如果是域)或数字(如果是IP地址)结尾。 每个域可以有一个子域。 根据标准,每个域的长度不能超过63个字符 总长度为255个字符 。 域嵌套在子域中 限制为127个域 。 不幸的是,Regex JavaScript引擎无法完全启用这些限制,但是您可以编写一个大致符合规则并通过测试的表达式。 消除了可以通过调整其他参数来避免的问题。
解决方案 /^https?:\/\/(((\b[az\d-]{1,63}\b)\.){1,40}(\b[az\d-]{1,63}\b))\/?$/i
解析解决方案- “ ^ https ?: \ / \ /”-http://或https://
让我们分别对其进行分析((\ b [az \ d-] {1,63} \ b)。){1,40}
- 域的结尾和开头应使用“ \ b”,以确保该域不以任何无效开头和结尾。
- 域名中包含“ [az \ d-] {1,63}”,字母,数字和连字符
- “ {1.63}”-全部不超过63个字符。
- “(((domain-name)。){1,40}”-我想在此处输入127,但是在正则表达式中,量词{,}表示重复间隔。 在使用[] {}的情况下-这是字符数,而在没有[]的情况下-这正是模板(域名)的重复数。 因此,我们将重复次数限制为40,以不超过总长度限制,因此我们也不能严格设置该长度限制。
任务8-重复元素
http://callumacrae.imtqy.com/regex-tuesday/challenge8.html
该任务在许多方面与任务1非常相似,但是在这里您需要查找并突出显示MarkDown列表中包含两个星号的重复元素。
这样的清单:
* Repeated list item * Repeated list item
必须转换为此:
* Repeated list item * **Repeated list item**
解决方案表达方式:
/^(\*\s+([^\n]+)\n\*\s+)(\2)$/gmi
更换:
$1**$3**
任务9-MarkDown链接
http://callumacrae.imtqy.com/regex-tuesday/challenge9.html
将有效的MarkDown链接替换为html链接。
转换范例:
[Another](http://example.com/) -> <a href="http://example.com/">Another</a>
提示可以完全不偷窥,也可以只是向前看。 不用回头,而是替代品。
解决方案表达方式:
/(^|\s+)\[([^\]\[]+)\]\s*\((https?:\/\/\b[az\d-]+\b(\.[az-]+)*\.\w+\/*)\)(?=$|\s+)/i
更换:
$1<a href="$3">$2</a>
解析解决方案- “(^ | \ s +)”-在MarkDown链接之前,允许行的开头或空格。 我们将其纳入组,以在替换$ 1中替换捕获的空间。
- “ [[([^] [] +)] \ s *”-标题中允许使用除方括号以外的任何字符。
- “(https ?: \ / \ / \ b [az \ d-] + \ b(。[az-] +) 。\ w + \ / )”-我们检查URL地址是否有效。
- “(?= $ | \ s +)”-在空格或行尾。
任务10-关键字
http://callumacrae.imtqy.com/regex-tuesday/challenge10.html
最艰巨的挑战。 使用带替换的正则表达式,将现有文本转换为以逗号分隔的关键字。
规则:
- 引号是一个关键词。
- 连字符是一个关键词。
- 该词可以包含撇号。
- 必须删除符号(;-'“)。
一个例子是这样的:
不要告诉Suzie Smith-Hopper我弄坏了Daniel的玩具马
应转换为:
不要告诉苏茜,史密斯-霍珀,我摔坏了,丹尼尔的玩具,马
乍一看听起来并不复杂,但事实并非如此。 事实是,只有一个正则表达式带有替换项,这样的问题才得以解决,并且无法最终解决。 但是测试用例的设计方式使所有这些都可以解决问题。
提示必须确定在何处放置逗号,该逗号旁边要替换的内容以及哪一侧。 问题中有一个假设-每个测试用例中的第一个单词都不需要任何更改。 这意味着您需要在替换单词的左边加上一个逗号,除了第一个单词。
解决方案表达方式:
/\s(['"])([^'"]+)\1|(;? |['"]? | ['"]|-{2,})(\w+)/g
更换:
,$2$4
解析解决方案由于我们已经确定了放置逗号的位置,因此我们将决定用什么替换该逗号以及删除什么。
- “ \ s(['”])([^'“] +)”-用{,带空格的单词 }替换模板{space“的单词在引号中 带有空格”} 。 这里的“ \ s”不仅是这样,而是为了排除引号放置错误的错误出现。
- “(;?| ['”]?| ['“] |-{2,})(\ w +)”-然后有单个单词,其前面需要删除的字符以及在这些单词之前的逗号。