我们通过了Callum Macrae的挑战100%

我建议尝试解决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>标记之前。
  • ((?!*)| $)-我们将以该行的结尾或除星号之外的任何字符结尾,因为在这里偷看-不会捕获空格。
  • “([[^ *]。*?[^ *] | [^ *])””-中间有“ [^ *]。*?[^ *]”任何不应该以星号和表达式开头和结尾的文本或“ | [^ *]”只是为了考虑标记内的单个字符(无需通过测试)。

任务5-数字格式


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 +)”-然后有单个单词,其前面需要删除的字符以及在这些单词之前的逗号。

Source: https://habr.com/ru/post/zh-CN474184/


All Articles