Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/404.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript正则表达式中的命名捕获组?_Javascript_Regex - Fatal编程技术网

JavaScript正则表达式中的命名捕获组?

JavaScript正则表达式中的命名捕获组?,javascript,regex,Javascript,Regex,据我所知,JavaScript中没有命名的捕获组。获得类似功能的替代方法是什么?ECMAScript 2018引入了JavaScript正则表达式 例如: const auth = 'Bearer AUTHORIZATION_TOKEN' const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth) console.log(token) // "Prints AUTHORIZATION_TOKEN"

据我所知,JavaScript中没有命名的捕获组。获得类似功能的替代方法是什么?

ECMAScript 2018引入了JavaScript正则表达式

例如:

  const auth = 'Bearer AUTHORIZATION_TOKEN'
  const { groups: { token } } = /Bearer (?<token>[^ $]*)/.exec(auth)
  console.log(token) // "Prints AUTHORIZATION_TOKEN"
如果您需要支持较旧的浏览器,您可以使用普通编号的捕获组来完成与命名捕获组相同的所有操作,您只需跟踪编号-如果正则表达式中捕获组的顺序发生变化,这可能会很麻烦

我能想到的命名捕获组的结构优势只有两个:

据我所知,在一些regex风格的.NET和JGSoft中,您可以在regex中为不同的组使用相同的名称。但大多数正则表达式风格无论如何都不支持此功能

如果您需要在数字包围的情况下引用编号的捕获组,您可能会遇到问题。假设您想在数字上加一个零,因此想用$10替换\d。在JavaScript中,只要您的正则表达式中的捕获组少于10个,这就可以工作,但Perl会认为您正在寻找的是反向引用编号10,而不是编号1,后面是0。在Perl中,在本例中可以使用${1}0

除此之外,命名捕获组只是语法糖。只有在您真正需要时才使用捕获组和使用非捕获组会有所帮助?:。。。在所有其他情况下

在我看来,JavaScript更大的问题是它不支持冗长的正则表达式,这将使创建可读、复杂的正则表达式变得更容易


解决了这些问题。

命名捕获的组提供了一件事:减少了对复杂正则表达式的混淆

这实际上取决于您的用例,但也许打印您的正则表达式会有所帮助

或者您可以尝试定义常量以引用捕获的组

然后,注释还可能有助于向阅读您的代码的其他人展示您所做的事情

对于其余部分,我必须同意Tims的回答。

您可以使用一个扩展的、可扩展的、跨浏览器的正则表达式实现,包括对其他语法、标志和方法的支持:

添加新的正则表达式和替换文本语法,包括对的全面支持。 添加两个新的正则表达式标志:s,使点匹配所有字符(也称为点或单行模式),x,表示自由间距和注释(也称为扩展模式)。 提供一套函数和方法,使复杂的正则表达式处理变得轻而易举。 自动修复正则表达式行为和语法中最常见的跨浏览器不一致。 允许您轻松创建和使用插件,为XRegExp的正则表达式语言添加新的语法和标志。
有一个名为node.js的库,您可以在浏览器中的node.js项目中使用它,方法是使用browserify或其他打包脚本打包该库。但是,该库不能与包含未命名捕获组的正则表达式一起使用


如果计算正则表达式中的开始捕获大括号,则可以在正则表达式中的命名捕获组和编号捕获组之间创建映射,并且可以自由混合和匹配。在使用正则表达式之前,只需删除组名。我已经编写了三个函数来证明这一点。请看以下要点:

虽然您不能用普通JavaScript实现这一点,但您可以使用一些Array.prototype函数,如Array.prototype.reduce,使用一些魔法将索引匹配转换为命名匹配

显然,以下解决方案需要按顺序进行匹配:

//@text包含要匹配的文本 //@regex A正则表达式对象f.e./+/ //@matchNames一个文本字符串数组,其中每个项 //是每个组的名称 函数名DregeXmatchText、正则表达式、匹配名{ var matches=regex.exectext; 返回匹配项。reducefunctionresult、匹配项、索引{ 如果索引>0 //这个减法是必需的,因为我们计数 //匹配1中的索引,因为0是完整的匹配字符串 结果[匹配名称[索引-1]]=匹配; 返回结果; }, {}; } var myString=你好,亚历克斯,我是约翰; var namedMatches=namedRegexMatch myString, /你好[a-z]+,我是[a-z]+/I, [第一个人姓名,第二个人姓名] ;
alertJSON.stringifynamedMatches 另一种可能的解决方案:创建一个包含组名和索引的对象

var regex = new RegExp("(.*) (.*)");
var regexGroups = { FirstName: 1, LastName: 2 };
然后,使用对象关键点参照组:

var m = regex.exec("John Smith");
var f = m[regexGroups.FirstName];

这可以使用正则表达式的结果提高代码的可读性/质量,但不能提高正则表达式本身的可读性。

在ES6中,您可以使用数组分解来捕获组:

let text = '27 months';
let regex = /(\d+)\s*(days?|months?|years?)/;
let [, count, unit] = regex.exec(text) || [];

// count === '27'
// unit === 'months'
注意:

最后一个let中的第一个逗号跳过结果数组的第一个值,即整个匹配字符串 当不存在匹配项时,| |[]after.exec将防止出现解构错误,因为 .exec将返回null 更新:它终于成为了JavaScriptECMAScript 2018

命名的捕获组很快就能变成JavaScript。

捕获组可以在角括号内使用?来命名?。。。语法,例如 任何标识符名称。日期的正则表达式可以是 写为/?\d{4}-?\d{2}-?\d{2}/u。每个名字 应该是唯一的,并遵循ECMAScript IdentifierName的语法

可以从的组属性访问命名组 正则表达式结果。对组的编号引用为 也创建了,与未命名组一样。例如:

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';

// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
正如Tim Pietzcker所说,ECMAScript 2018在JavaScript正则表达式中引入了命名捕获组。 但是我在上面的答案中没有发现如何在正则表达式中使用命名的捕获组

您可以使用以下语法使用命名捕获组:\k。 比如说

var regexObj = /(?<year>\d{4})-(?<day>\d{2})-(?<month>\d{2}) year is \k<year>/
var regexObj=/?\d{4}-?\d{2}-?\d{2}年为\k/mgi; 功能检查{ var inp=document.getElementByIdtinput.value; 让结果=regexObj.execinp; document.getElementByIdyear.innerHTML=result.groups.year; document.getElementByIdmonth.innerHTML=result.groups.month; document.getElementByIdday.innerHTML=result.groups.day; } td,th{ 边框:实心2件ccc; } 模式:?\d{4}-?\d{2}-?\d{2}年为\k; 检查 年 月 白天
没有ECMAScript 2018

我的目标是使它的工作方式尽可能类似于我们习惯于命名组的工作方式。而在ECMAScript 2018中,您可以放置?在用于指示命名组的组内,在我的旧javascript解决方案中,您可以放置在小组内部做同样的事情。这是一组额外的括号和一个额外的!=。非常接近

我将所有内容包装到一个字符串原型函数中

特征

使用较旧的javascript 没有额外的代码 使用起来非常简单 正则表达式仍然有效 组记录在regex本身中 组名可以有空格 返回包含结果的对象 指示

地方={groupname}在每个要命名的组中 请记住,通过在组的开头添加?:来消除任何未捕获的组。这些不会被命名。 arrays.js


javascript中的捕获组是按编号排列的。$1是第一个捕获的组,$2,$3。。。高达99美元,但听起来你想要别的东西,而事实并非如此exist@Erik你说的是编号捕获组,OP说的是命名捕获组。它们是存在的,但我们想知道JS中是否有对它们的支持。有一个,但可能要过几年才能看到,如果我们有。Firefox惩罚我试图在网站上使用命名捕获组。。。真是我自己的错。许多风格允许在正则表达式中多次使用相同的捕获组名。但是只有.NET和Perl 5.10+通过保留参与匹配的名称的最后一组所捕获的值,使这一点特别有用。最大的优势是:您只需更改RegExp,而无需将数字映射为变量。非捕获组解决了这个问题,但有一种情况除外:如果组的顺序发生变化怎么办?另外,把这些额外的字符放在其他组上也是一种注释……所谓的语法糖确实有助于提高代码的可读性!我认为命名捕获组还有另一个真正有价值的原因。例如,如果您想使用正则表达式来解析字符串中的日期,那么可以编写一个灵活的函数来接受该值和正则表达式。只要正则表达式指定了年份、月份和日期的捕获,您就可以用最少的代码运行正则表达式数组。截至2019年10月,Firefox、IE 11和Microsoft Edge pre Chromium不支持命名组捕获。大多数其他浏览器甚至包括Opera和三星手机都有。那很酷。我只是在想。。难道不可能创建一个接受自定义正则表达式的正则表达式函数吗?这样你就可以像var Assocaray=Regexello alex一样,我是丹尼斯,你好{hisName}.+,我是{yourName}.+@显然,您可以进一步开发此功能。让它工作起来并不难:DYou可以通过向其原型添加函数来扩展RegExp对象。@Mr.TA AFAIK,不建议扩展内置对象第一个逗号是因为match返回的数组的第一个元素是输入表达式,对吗?String.prototype.match返回一个数组:位置0处的整个匹配字符串,然后是其后的任何组。第一个逗号表示跳过位置0处的元素。对于那些有transpiling或ES6+目标的人,这里是我最喜欢的答案。这并不一定能防止不一致性错误,如果重复使用的正则表达式发生变化,命名索引也能防止不一致性错误,但我认为这里的简洁性很容易弥补这一点。我选择了RegExp.prototype.exec而不是String.p
rototype.match在字符串可能为null或未定义的位置。这是一个惊人的轻量级,我将尝试它。它是否适用于复杂正则表达式中正则组中的嵌套命名组?它并不完美。错误发生在:getMapa | b:c;foo应该是第三组,而不是第二组/a | bc/g.execbc;[bc,bc,bc,c]现在是第4阶段的提案。如果你使用的是'18,那么不妨全部使用解构;让{年、月、日}=result=>result?结果.分组:{}re.exec'2015-01-02';在名为捕获组的情况下,也可以使用空合并:让{year,month,day}={…re.exec'2015-01-02'?.groups};
let result = regexObj.exec('2019-28-06 year is 2019');
// result.groups.year === '2019';
// result.groups.month === '06';
// result.groups.day === '28';
// @@pattern - includes injections of (?!={groupname}) for each group
// @@returns - an object with a property for each group having the group's match as the value 
String.prototype.matchWithGroups = function (pattern) {
  var matches = this.match(pattern);
  return pattern
  // get the pattern as a string
  .toString()
  // suss out the groups
  .match(/<(.+?)>/g)
  // remove the braces
  .map(function(group) {
    return group.match(/<(.+)>/)[1];
  })
  // create an object with a property for each group having the group's match as the value 
  .reduce(function(acc, curr, index, arr) {
    acc[curr] = matches[index + 1];
    return acc;
  }, {});
};    
function testRegGroups() {
  var s = '123 Main St';
  var pattern = /((?!=<house number>)\d+)\s((?!=<street name>)\w+)\s((?!=<street type>)\w+)/;
  var o = s.matchWithGroups(pattern); // {'house number':"123", 'street name':"Main", 'street type':"St"}
  var j = JSON.stringify(o);
  var housenum = o['house number']; // 123
}
{
  "house number": "123",
  "street name": "Main",
  "street type": "St"
}