似乎我找不到一个正则表达式能够做到这一点,而且如果匹配部分出现在字符串开头时就会失败。 负向后查找似乎是唯一的答案,但JavaScript并没有这个功能。
这是我想要使用的正则表达式,但它不能正常工作:
(?<!([abcdefg]))m
所以它将匹配'jim'或'm'中的'm',但不会匹配'jam'。
似乎我找不到一个正则表达式能够做到这一点,而且如果匹配部分出现在字符串开头时就会失败。 负向后查找似乎是唯一的答案,但JavaScript并没有这个功能。
这是我想要使用的正则表达式,但它不能正常工作:
(?<!([abcdefg]))m
所以它将匹配'jim'或'm'中的'm',但不会匹配'jam'。
// positive lookbehind
(?<=...)
// negative lookbehind
(?<!...)
2018年以前的回答
由于Javascript支持负向先行断言,一种方法是:
反转输入字符串
使用反转的正则表达式进行匹配
将匹配结果反转并重新格式化
const reverse = s => s.split('').reverse().join('');
const test = (stringToTests, reversedRegexp) => stringToTests
.map(reverse)
.forEach((s,i) => {
const match = reversedRegexp.test(s);
console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
});
例子1:
根据@andrew-ensley的问题:
test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)
输出:
jim true token: m
m true token: m
jam false token: Ø
例子2:
根据@neaumusic的评论(匹配max-height
但不匹配line-height
,令牌为height
):
test(['max-height', 'line-height'], /thgieh(?!(-enil))/)
输出:
max-height true token: height
line-height false token: Ø
max-height
但不是 line-height
,而且我只想匹配 height
。 - neaumusic''(?!\()
将从另一端替换''(''test'''''''test
中的撇号,因此留下(''test'NNNtest
而不是(''testNNN'test
。 - Wiktor StribiżewPositive lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<=\$)\d+\.\d*/) // Matches "9.99"
);
Negative lookbehind usage:
console.log(
"$9.99 €8.47".match(/(?<!\$)\d+\.\d*/) // Matches "8.47"
);
假设您想查找所有未在unsigned
之前的int
:
使用负回顾支持:
(?<!unsigned )int
没有负回顾支持:
((?!unsigned ).{9}|^.{0,8})int
基本思想是获取前n个字符并排除与负向预查的匹配,但也要匹配没有前n个字符的情况。这里的 n 是后置断言的长度。
因此,所讨论的正则表达式为:
(?<!([abcdefg]))m
将会被翻译为:
((?!([abcdefg])).|^)m
你可能需要使用捕获组来找到你感兴趣或想替换特定部分的字符串的确切位置。
"So it would match the 'm' in 'jim' or 'm', but not 'jam'".replace(/(j(?!([abcdefg])).|^)m/g, "$1[MATCH]")
返回结果为
"So it would match the 'm' in 'ji[MATCH]' or 'm', but not 'jam'"
。
很简单,而且它有效! - AsrailMijoja的策略对于你具体的情况有效,但不适合所有情况:
js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]ama
以下是一个示例,目标是匹配双“l”,但不要在其前面加上“ba”。请注意单词“balll” - 真实的后顾应该抑制了前两个“l”,但匹配了第二对。但通过匹配前两个“l”,然后将其视为误报,正则表达式引擎从该匹配的结尾继续,并忽略误报中的任何字符。
newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});
newString
始终等于string
。为什么会有这么多赞? - MikeM"Jim Jam Momm m".replace(/([abcdefg])?m/g, function($0, $1){ return $1 ? $0 : '[match]'; });
。它应该返回 Ji[match] Jam Mo[match][match] [match]
。但请注意,正如Jason在下面提到的那样,它在某些边缘情况下可能会失败。 - Simon East你可以通过否定字符集来定义一个非捕获组:
(?:[^a-g])m
...这将匹配每个未被任何这些字母之一前置的m
。
(?:[^a-g]|^)m
。请参见 https://regex101.com/r/jL1iW6/2 以获取运行示例。 - Johny Skovdal这是我在 Node.js 8 中实现 str.split(/(?<!^)@/)
(因为不支持后顾断言)的方式:
最初的回答:
str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()
能用吗?可以(unicode未经测试)。舒适度如何?不太好。
最初的回答:
在Mijoja的思路基础上,结合JasonS提出的问题,我有了这个想法;我进行了一些检查,但不确定自己是否正确,因此希望有比我更专业的js正则表达式方面的人进行验证:)
var re = /(?=(..|^.?)(ll))/g
// matches empty string position
// whenever this position is followed by
// a string of length equal or inferior (in case of "^")
// to "lookbehind" value
// + actual value we would want to match
, str = "Fall ball bill balll llama"
, str_done = str
, len_difference = 0
, doer = function (where_in_str, to_replace)
{
str_done = str_done.slice(0, where_in_str + len_difference)
+ "[match]"
+ str_done.slice(where_in_str + len_difference + to_replace.length)
len_difference = str_done.length - str.length
/* if str smaller:
len_difference will be positive
else will be negative
*/
} /* the actual function that would do whatever we want to do
with the matches;
this above is only an example from Jason's */
/* function input of .replace(),
only there to test the value of $behind
and if negative, call doer() with interesting parameters */
, checker = function ($match, $behind, $after, $where, $str)
{
if ($behind !== "ba")
doer
(
$where + $behind.length
, $after
/* one will choose the interesting arguments
to give to the doer, it's only an example */
)
return $match // empty string anyhow, but well
}
str.replace(re, checker)
console.log(str_done)
我的个人输出:
Fa[match] ball bi[match] bal[match] [match]ama
checker
,每当该位置是以下内容的起始点时:'ba'
,因此是..
)的任何子字符串(如果已知该大小;否则可能更难做到)^.?
然后,在此之后,'ll'
)。checker
时,将进行测试以检查ll
之前的值是否不是我们不想要的(!== 'ba'
);如果是这种情况,则调用另一个函数,它必须是这个函数(doer
),如果目的是这个,那么它将对str进行更改,或者更一般地说,它将获得输入来手动处理扫描str
的结果所需的数据。
在这里,我们更改了字符串,因此需要保留长度差异的跟踪,以便抵消由replace
给出的位置,所有这些都是在str
上计算的,它本身永远不会改变。
由于原始字符串是不可变的,我们可以使用变量str
来存储整个操作的结果,但我认为例子已经被替换复杂化了,使用另一个变量(str_done
)会更清晰。
我想在性能方面,这可能非常严格:所有这些毫无意义的''到''的替换,this str.length-1
次,加上手动替换,这意味着大量的切片......
在这个特定的例子中,可能可以通过仅将字符串切成围绕我们要插入的地方的片段,并使用[match]
本身进行.join()
来进行分组。
另一件事是,我不知道它如何处理更复杂的情况,也就是虚假后顾的复杂值......长度可能是最难处理的数据。
在checker
中,如果$behind存在多个不想要的值的可能性,我们将不得不使用另一个正则表达式对其进行测试(最好在checker
之外缓存(创建),以避免在每次调用checker
时创建相同的正则表达式对象),以知道它是否是我们要避免的内容。"jim jam".replace(/([^a-g])m/g, "$1M")
\\jiM jam
([^a-g])
将匹配a-g
范围之外的任何字符,并将其存储在第一个捕获组中,因此您可以使用$1
访问它。
因此,我们在jim
中找到im
并用iM
替换它,结果为jiM
。
(?<!Before)Wanted
,其中 Wanted
是你想匹配的正则表达式,Before
是计算出什么不应该在匹配之前的正则表达式。你所能做的最好的事情就是否定正则表达式 Before
并使用正则表达式 NotBefore(Wanted)
。期望的结果是第一个组 $1
。Before=[abcdefg]
,很容易否定 NotBefore=[^abcdefg]
。所以正则表达式将是 [^abcdefg](m)
。如果你需要 Wanted
的位置,你必须把 NotBefore
也分组,这样期望的结果就是第二个组。Before
模式的匹配具有固定长度n
(即,如果该模式不包含重复标记),则可以避免否定Before
模式,并使用正则表达式(?!Before).{n}(Wanted)
,但仍需使用第一组或使用正则表达式(?!Before)(.{n})(Wanted)
并使用第二组。在此示例中,模式Before
实际上具有固定长度,即1,因此使用正则表达式(?![abcdefg]).(m)
或(?![abcdefg])(.)(m)
。如果您对所有匹配感兴趣,请添加g
标志,查看我的代码片段:function TestSORegEx() {
var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
var reg = /(?![abcdefg])(.{1})(m)/gm;
var out = "Matches and groups of the regex " +
"/(?![abcdefg])(.{1})(m)/gm in \ns = \"" + s + "\"";
var match = reg.exec(s);
while(match) {
var start = match.index + match[1].length;
out += "\nWhole match: " + match[0] + ", starts at: " + match.index
+ ". Desired match: " + match[2] + ", starts at: " + start + ".";
match = reg.exec(s);
}
out += "\nResulting string after statement s.replace(reg, \"$1*$2*\")\n"
+ s.replace(reg, "$1*$2*");
alert(out);
}
(?:[^abcdefg]|^)(m)
呢?就像"mango".match(/(?:[^abcdefg]|^)(m)/)[1]
这样。 - slebetman