嘿那里,你是正则表达的恋人!
这些时候,我在Regex中,并且有一个纯粹的理论问题.简单来说,我会把它作为一个游戏来呈现.
游戏:
 
假设你有一个由空格分隔的单词列表.
我称之为单词是因为它们是由正则表达式定义的:( [a-zA-Z_0-9]+这里没有空字)
列表示例:
Horse Banana Joker RoXx0r A_Long_Word Joker 1337
我要你做的是将除了Joker之外的每个单词替换为$等于字符数的$匹配的单词.
通过我们之前的列表,我们将获得:
$$$$$ $$$$$$ Joker $$$$$$ $$$$$$$$$$$ Joker $$$$
用更少的单词: 我想要一个正则表达式匹配每个不属于单词"Joker"的字符(在字符串中,我的意思是,不是那个组成单词Joker)
虽然这并不容易,这不是不可能的(我有自己的正则表达式).这就是为什么我会制定一些规则.
规则 :
添加规则:
为了帮助你,这里有正则表达式必须工作的一些字符串:
Horse Banana Joker RoXx0r A_Long_Word Joker 1337 Joke Poker Joker Jokers
更换
$$$$$ $$$$$$ Joker $$$$$$ $$$$$$$$$$$ Joker $$$$ $$$$ $$$$$ Joker $$$$$$
Joker Joker Joker
后必须返回:更换后必须返回:
Joker Joker Joker
再次,解决问题不是这里的目标,我希望看到不同的解决方案,更重要的是我希望看到最好的解决方案!
解决方案:
 
一个非常优雅的一个由卡西米尔等伊波利特:
 
(?:\G(?!^)|(?<!\S)(?!Joker(?:\s|$)))\S(更换:$)
查看信息
 
.然而\ G变走的乐趣出了问题,并在每一种语言是不行的,所以除非是有可能创建我无法接受自定义分隔符是相当于一个\ g 
几乎公认的答案也卡西米尔等伊波利特:
((?:\s+|\bJoker\b)*)\S((?:\s+Joker)*\s*$)?(更换:$1$$2)
查看信息
 
时,有字符串中唯一的小丑的话也不行
类似的解决方案通过ClasG:
(\bJoker[^\w]+)\w|\w([^\w]+Joker\b)|\w(更换:$1$$2)
查看信息
 
当有字符串中唯一的小丑的话不起作用
另一条由ClasG:
[^Joker\s]|(?<!\b)J|J(?!oker\b)|(?<!\bJ)o|o(?!ker\b)|(?<!\bJo)k|k(?!er\b)|(?<!\bJok)e|e(?!r\b)|(?<!\bJoke)r|r(?!\b)(更换:$)
查看信息
 
不是很有效,虽然,但它是看待事物的另一种方式;)
我想出了一个类似的正则表达式看完后评论下面的Rahul :( 
(?(?<=\b|\bJ|\bJo|\bJok|\bJoke|\bJoker)(?!(?:Joke|oke|ke|e|)r\b)\w|\w)替换$)
Regex101
 
这也是低效的,但使用相同的外观列表的东西:)
这是我的第一个解决方案:
我使用的技巧可能被视为作弊,但我没有,因为它不会改变你用来替换字符的功能.在将字符替换为字符串之前,您只需在字符串末尾添加"$".
因此,而不是像这样:
string = replace(string, regex, '$1$2')
我们将有:
string = replace(string+'$', regex, '$1$2')
因此,这里的正则表达式:
(\bJoker\b)|.$|\w(?=.*(\$))(更换:$1$2)
正则表达式101
 
这应该与除了那些不支持向前看符号所有语言(他们是相当罕见的),
请在发布新的正则表达式,如果你找到的,我想看到更多的方法来做到这一点!:)
适用于 PCRE/Perl/Ruby/Java/.net
寻找:
(?:\G(?!^)|(?<!\S)(?!Joker(?!\S)))\S
代替:
$
图案细节:
(?:
    \G (?!^) # contigous to a previous match (but not at the start of the string)
  |        # OR
    (?<!\S)  # not preceded by a non white-space
    (?!Joker(?!\S)) # not followed by the forbidden word
)
\S   # a non-whitespace character
如果您的单词仅由单词字符组成,您可以简化使用单词和非单词边界的模式:(?:\G\B|\b(?!Joker\b))\w
其他方式(PCRE/Perl):没有该\G功能并带有回溯控制动词(*SKIP)(需要更少的步骤):
\s*(?:Joker(?:\s+|$))*(*SKIP)\K.
(*SKIP)仅当字符串以禁止词或空格结尾时,清晰才有用。您也可以将其替换为(*COMMIT).
或者:
\bJoker\b(*SKIP)(*F)|\S
并使用 pypi python 正则表达式模块(该模块有一个用于开头的单词边界和一个用于单词结尾的单词边界):
\mJoker\M(*SKIP)(*F)|\S
一个与 Javascript 一起使用的(如果有东西需要替换的话):
寻找:
((?:\s+|\bJoker\b)*)\S((?:\s+Joker)*\s*$)?
替换:(对组 1 的反向引用,转义 $,对组 2 的反向引用)
$1$$$2 
另一种 Javascript 版本使用 y 标志(强制匹配连续),但不幸的是,Internet Explorer、Safari 和移动浏览器(除 Firefox mobile 外)不支持此版本:
var strs = ['Horse Banana Joker RoXx0r A_Long_Word Joker 1337 Joke Poker Joker', 'Joker Joker Joker'];
strs.forEach(function (s) {
    console.log(s.replace(/(?=((?:\s+|\bJoker\b)*))\1./gy, '$1$$'));
});
模拟(?=(...))\1一个原子组(禁止回溯)。