RegEx 替换 returns 不带 .* 的意外结果
RegEx replace returns unexpected result without .*
我正在尝试创建一个执行以下转换的正则表达式:
Apple Orange
> AO
Load Module
> LM
anApple Orange
> O
toLoad Module
> M
我找到了合适的模式,但发现了一个奇怪的行为。这是我的初步尝试:
/^([A-Z])?[^ ]* ([A-Z])/
运行 用这个表达式替换第三个(和第四个)测试用例给了我一个令人惊讶的结果:
'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z])/,'')
> "Orange"
为什么这令人惊讶?嗯,第一组明显不匹配,因为字符串不是以大写字母开头的,但是第二组只选了一个单个大写字母:([A-Z])
,不是全部在它之后:([A-Z].*)
令我惊讶的是,在最后一个捕获组之后添加 .*
给了我正确的结果:
'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z]).*/,'')
> "O"
为什么会发生这种情况超出了我对 JS 和正则表达式的理解。我很高兴知道是什么黑魔法导致单个 [A-Z]
到 return 多个,甚至是一些小写字符。
这是一个可运行的演示:
var testCases = [
'Apple Orange',
'Load Module',
'anApple Orange',
'toLoad Module'
],
badregex = /^([A-Z])?[^ ]* ([A-Z])/,
goodregex = /^([A-Z])?[^ ]* ([A-Z]).*/;
document.onreadystatechange = function(n){
if (document.readyState === "complete"){
for (var i=0,l=testCases.length; i<l; i++){
var p = document.createElement('p'),
testCase = testCases[i];
p.innerHTML = ""+testCase+" > "+testCase.replace(badregex,'')
document.body.appendChild(p);
}
document.body.appendChild(document.createElement('hr'));
for (var i=0,l=testCases.length; i<l; i++){
var p = document.createElement('p'),
testCase = testCases[i];
p.innerHTML = ""+testCase+" > "+testCase.replace(goodregex,'')
document.body.appendChild(p);
}
}
}
我愿意,
> "Apple Orange".replace(/(?:^|\s)([A-Z])|./g, "")
'AO'
不要把事情复杂化。只需捕获 space 之后或开头的所有大写字符。然后匹配所有剩余的字符。现在用 </code> 替换所有匹配的字符。请注意,所有匹配的字符都将替换为替换部分中存在的字符。</p>
<p><a href="https://regex101.com/r/rV0iE9/2" rel="nofollow">DEMO</a></p>
<p>为什么?</p>
<pre><code>'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z])/,'')
> "Orange"
([A-Z])?
检查开头的可选大写字母。哪有这回事。所以它捕获了一个空字符串。
[^ ]*
匹配零个或多个非 space 字符。
<space>
匹配 space.
([A-Z])
仅捕获 Orange 中的第一个字母。
- 现在用
</code> 替换所有匹配的字符 -> 空字符串 <code>
-> O
会给你 Orange
您的第一个示例匹配 anApple O
。 </code> 为空,因为 <code>^([A-Z])?
是可选的且不匹配,并且 </code> 是 <code>O
,因此您将 anApple O
替换为 O
字符串 anApple Orange
这将导致 Orange
您可以使用带有 match
的非常简单的正则表达式,并使用 join
来获得所需的输出,而不是将 replace
与复杂的正则表达式一起使用:
'anApple Orange'.match(/\b([A-Z])/g).join('')
//=> O
'Apple Orange'.match(/\b([A-Z])/g).join('')
//=> AO
我正在尝试创建一个执行以下转换的正则表达式:
Apple Orange
>AO
Load Module
>LM
anApple Orange
>O
toLoad Module
>M
我找到了合适的模式,但发现了一个奇怪的行为。这是我的初步尝试:
/^([A-Z])?[^ ]* ([A-Z])/
运行 用这个表达式替换第三个(和第四个)测试用例给了我一个令人惊讶的结果:
'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z])/,'')
> "Orange"
为什么这令人惊讶?嗯,第一组明显不匹配,因为字符串不是以大写字母开头的,但是第二组只选了一个单个大写字母:([A-Z])
,不是全部在它之后:([A-Z].*)
令我惊讶的是,在最后一个捕获组之后添加 .*
给了我正确的结果:
'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z]).*/,'')
> "O"
为什么会发生这种情况超出了我对 JS 和正则表达式的理解。我很高兴知道是什么黑魔法导致单个 [A-Z]
到 return 多个,甚至是一些小写字符。
这是一个可运行的演示:
var testCases = [
'Apple Orange',
'Load Module',
'anApple Orange',
'toLoad Module'
],
badregex = /^([A-Z])?[^ ]* ([A-Z])/,
goodregex = /^([A-Z])?[^ ]* ([A-Z]).*/;
document.onreadystatechange = function(n){
if (document.readyState === "complete"){
for (var i=0,l=testCases.length; i<l; i++){
var p = document.createElement('p'),
testCase = testCases[i];
p.innerHTML = ""+testCase+" > "+testCase.replace(badregex,'')
document.body.appendChild(p);
}
document.body.appendChild(document.createElement('hr'));
for (var i=0,l=testCases.length; i<l; i++){
var p = document.createElement('p'),
testCase = testCases[i];
p.innerHTML = ""+testCase+" > "+testCase.replace(goodregex,'')
document.body.appendChild(p);
}
}
}
我愿意,
> "Apple Orange".replace(/(?:^|\s)([A-Z])|./g, "")
'AO'
不要把事情复杂化。只需捕获 space 之后或开头的所有大写字符。然后匹配所有剩余的字符。现在用 </code> 替换所有匹配的字符。请注意,所有匹配的字符都将替换为替换部分中存在的字符。</p>
<p><a href="https://regex101.com/r/rV0iE9/2" rel="nofollow">DEMO</a></p>
<p>为什么?</p>
<pre><code>'anApple Orange'.replace(/^([A-Z])?[^ ]* ([A-Z])/,'')
> "Orange"
([A-Z])?
检查开头的可选大写字母。哪有这回事。所以它捕获了一个空字符串。[^ ]*
匹配零个或多个非 space 字符。<space>
匹配 space.([A-Z])
仅捕获 Orange 中的第一个字母。- 现在用
</code> 替换所有匹配的字符 -> 空字符串 <code>
->O
会给你Orange
您的第一个示例匹配 anApple O
。 </code> 为空,因为 <code>^([A-Z])?
是可选的且不匹配,并且 </code> 是 <code>O
,因此您将 anApple O
替换为 O
字符串 anApple Orange
这将导致 Orange
您可以使用带有 match
的非常简单的正则表达式,并使用 join
来获得所需的输出,而不是将 replace
与复杂的正则表达式一起使用:
'anApple Orange'.match(/\b([A-Z])/g).join('')
//=> O
'Apple Orange'.match(/\b([A-Z])/g).join('')
//=> AO