Javascript 不排除点的Regexp组
假设我有以下字符串:Javascript 不排除点的Regexp组,javascript,regex,Javascript,Regex,假设我有以下字符串:div.classOneA.classOneB#idOne 试图编写一个从中提取类(classOneA,classOneB)的regexp。我能做到这一点,但只需要一点时间 看起来是这样的: 'div.classOneA.classOneB#idOne'.match(/(?<=\.)([^.#]+)/g) > (2) ["classOneA", "classOneB"] 虽然分组可以解决我的问题,但所有匹配项也包含点 如果您知道正在搜索包含类的文本,则可以使用
div.classOneA.classOneB#idOne
试图编写一个从中提取类(classOneA,classOneB)的regexp。我能做到这一点,但只需要一点时间
看起来是这样的:
'div.classOneA.classOneB#idOne'.match(/(?<=\.)([^.#]+)/g)
> (2) ["classOneA", "classOneB"]
虽然分组可以解决我的问题,但所有匹配项也包含点 如果您知道正在搜索包含
类的文本,则可以使用
'div.classOneA.classOneB#idOne'.match(/class[^.#]+/g)
如果您只知道文本前面有一个点,则必须使用lookback。此正则表达式在没有lookback断言的情况下工作:
'div.classOneA.classOneB#idOne'.match(/\.[^\.#]+/g).map(item => item.substring(1));
最近JavaScript中没有Lookbehind断言。如果您想扩展regex。您可以简单地对结果进行映射
,并用空字符串替换
let op='div.classOneA.classOneB#idOne'。匹配(/\.([^.#]+)/g)
.map(e=>e.replace(/\./g'))
log(op)
在Javascript中,没有一种好方法可以同时匹配多次(/g选项)和拾取捕获组(在参数中)。试试这个:
var input = "div.classOneA.classOneB#idOne";
var regex = /\.([^.#]+)/g;
var matches, output = [];
while (matches = regex.exec(input)) {
output.push(matches[1]);
}
我不是使用正则表达式的专家——特别是在Javascript中——但在对MDN进行了一些研究之后,我已经弄明白了为什么您的尝试不起作用,以及如何修复
问题是使用.match
与带有/g
标志的regexp匹配。因此,您必须在regexp对象上使用该方法,使用循环多次执行它以获得所有结果
所以下面的代码是有效的,并且可以适用于类似的情况。(注意grp[1]
-这是因为.exec
返回的数组的第一个元素是整个匹配项,组是后续元素。)
var regExp=/\([^.\]+)/g
var结果=[];
var-grp;
while((grp=regExp.exec('div.classOneA.classOneB#idOne'))!==null){
结果:推(grp[1]);
}
log(result)
这是因为使用g
修饰符可以得到所有匹配的子字符串,而不是它的匹配组(这就好像(…)
对的工作方式与(?:…)
对一样
你看。Whithoutg
修饰符:
> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/)
[ '.classOneA',
'classOneA',
index: 3,
input: 'div.classOneA.classOneB#idOne',
groups: undefined ]
> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/g)
[ '.classOneA', '.classOneB' ]
使用g
修饰符:
> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/)
[ '.classOneA',
'classOneA',
index: 3,
input: 'div.classOneA.classOneB#idOne',
groups: undefined ]
> 'div.classOneA.classOneB#idOne'.match(/\.([^.#]+)/g)
[ '.classOneA', '.classOneB' ]
换句话说:您获得所有匹配项,但每次仅获得整个匹配项(0项)
有许多解决方案:
使用您自己指出的LookBehind断言
稍后添加.map(x=>x.replace(/^\./,“”)修复每个结果
或者,如果您的输入结构不会比您提供的示例复杂得多,只需使用更便宜的方法:
> 'div.classOneA.classOneB#idOne'.replace(/#.*/, "").split(".").slice(1)
[ 'classOneA', 'classOneB' ]
使用.replace()
+回调而不是.match()
,以便能够访问每个匹配的捕获组:
const str = 'div.classOneA.classOneB#idOne';
const matches = [];
str.replace(/\.([^.#]+)/g, (...args)=>matches.push(args[1]))
console.log(matches); // [ 'classOneA', 'classOneB' ]
我会推荐第三种(如果没有其他可能的输入最终会破坏它的话),因为它效率更高(实际的正则表达式只用于修剪“#idOne”部分一次)。你就在我前面:-)哇,第四种解决方案相当棘手。不会想到用这种方式替换。感谢您的努力,尽管我已经接受了一个答案。我这样做只是为了好玩:-)尽管您的问题可能看起来是过早的优化,但也确实有很强的理由避免使用lookback方法:首先,因为lookaround操作是正则表达式实现中最昂贵的操作之一在那些经常执行的代码中,避免使用它们是个好主意……另一方面,正是因为这个原因,它们在ES6之前(如果我没记错的话)在javascript中是不可用的,所以如果你的代码需要在旧的javascript引擎中运行,lookaround方法是不可行的。我没有时间这么做,但是replace方法可以实现mathcString()函数,甚至重载String.match()方法(我不建议这样做,因为它是反模式),但这可能是一个有趣的练习…