繁体   English   中英

通过 Javascript 在一次匹配中获取多个正则表达式匹配结果

[英]Get multiple regex match result all in one match by Javascript

我试图通过删除那些重复代码来使我的代码看起来很专业。 问题是我想从字符串中获取一些数据,具体来说,我需要知道NUMBERXYZAB等值,但正则表达式对于每个变量都是不同的,所以我必须重复自己写了很多重复的代码。

 let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`; const regNumber = /(?<=NUMBER:=)[0-9]+/gm; let lineNumber = Number(TextString.match(regNumber)); const regX = /(?<=X:=)(-?[0-9]+)(.[0-9]+)?/gm; let X = Number(TextString.match(regX)).toFixed(1); const regY = /(?<=Y:=)(-?[0-9]+)(.[0-9]+)?/gm; let Y = Number(TextString.match(regY)).toFixed(1); const regZ = /(?<=Z:=)(-?[0-9]+)(.[0-9]+)?/gm; let Z = Number(TextString.match(regZ)).toFixed(1); const regA = /(?<=A:=)(-?[0-9]+)(.[0-9]+)?/gm; let A = Number(TextString.match(regA)).toFixed(1); const regB = /(?<=B:=)(-?[0-9]+)(.[0-9]+)?/gm; let B = Number(TextString.match(regB)).toFixed(1); // and many more duplicate code. console.log(lineNumber, X, Y, Z, A, B);

我只能想到像上面这样的方法,分别匹配每个变量并多次运行.match() ,但正如您所看到的,总共有 17 个变量,而在实际情况中,有数百个这样的TextString 我担心这个匹配过程会对性能产生巨大影响。

还有其他方法可以在一次匹配中获取所有变量并将它们存储在数组或对象中吗? 或任何其他优雅的方式来做到这一点?

每个坐标都有一个字母标识符,因此您可以使用更通用的正向回顾(?<=,[AZ]:=) 此回顾匹配一个逗号后跟一个大写字母然后是相等符号。

然后,您可以使用.match()获取所有匹配项并使用.map()运行您正在执行的转换。

 let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`; const regNumber = /(?<=NUMBER:=)[0-9]+/gm; let lineNumber = Number(TextString.match(regNumber)); const regex = /(?<=,[AZ]:=)(-?[0-9]+)(.[0-9]+)?/gm; let coord = TextString.match(regex).map(n => Number(n).toFixed(1)); console.log(lineNumber, coord);

每个值都匹配一个模式:=[value],:=[value])最后一个。 所以有我的正则表达式

(?<=:=)-?[\d\w.']+(?=[,)])

  • Positive Lookbehind (?<=:=):=后面寻找匹配项
  • -? 匹配-可选(对于负数)
  • [\d\w.']+ :匹配数字、单词字符、 . , '
  • Positive Lookahead (?=[,)])寻找匹配的超前字符,)

现场 regex101.com 演示

现在将您的代码更改为

 let TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`;
 const regexPattern= /(?<=:=)-?[\d\w.']+(?=[,)])/g;
 console.log(TextString.match(regexPattern))
 // ['20', "'4'", '1', '10.1', '73.344', '0', '-1.435', '1.045', '1', '2', '3', '4', '1', '10.5', '2.1', '1.2', '2', '2.4', '1', '2']

你可以写一个单一的模式:

(?<=\b(?:NUMBER|[XYZAB]):=)-?\d+(?:\.\d+)?\b

解释

  • (?<= Positive lookbehind, assert that to the left of the current position is
    • \b(?:NUMBER|[XYZAB]):=匹配NUMBERX Y Z A B中的一个,前面是单词边界,后面是:=
  • )关闭lookbehind
  • -? 匹配一个可选的-
  • \d+(?:\.\d+)? 匹配 1+ 个数字和一个可选的小数部分
  • \b防止部分单词匹配的单词边界

请参阅正则表达式演示

 const TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`; const regNumber = /(?<=\b(?:NUMBER|[XYZAB]):=)-?\d+(?:\.\d+)?\b/g; const result = TextString.match(regNumber).map(s => Number(s).toFixed(1) ); console.log(result);

这是一个在感兴趣的键上使用.reduce()并返回一个对象的解决方案:

 const TextString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`; const keys = [ 'NUMBER', 'X', 'Y', 'Z', 'A', 'B' ]; let result = keys.reduce((obj, key) => { const regex = new RegExp('(?<=\\b' + key + ':=)-?[0-9.]+'); obj[key] = Number(TextString.match(regex)).toFixed(1); return obj; }, {}); console.log(result);

输出:

{
  "NUMBER": "20.0",
  "X": "10.1",
  "Y": "73.3",
  "Z": "0.0",
  "A": "-1.4",
  "B": "1.0"
}

笔记:

  • 正则表达式是从密钥动态构建的
  • \b单词边界添加到正则表达式以减少意外匹配的机会
  • 如果您需要行号作为整数,您可以将其从keys中取出,并单独处理。

一种可能的方法是基于使用捕获组(或命名捕获组)的正则表达式模式。 OP 示例文本的匹配正则表达式如下所示......

/NUMBER\:=(?<number>[^,]+),.*?X:=(?<x>[^,]+),.*?Y:=(?<y>[^,]+),.*?Z:=(?<z>[^,]+),.*?A:=(?<a>[^,]+),.*?B:=(?<b>[^,]+)/g

...并且描述随正则表达式的测试站点一起提供。

利用基于数组的解构赋值来一次分配所有 OP 变量,可以将matchAll的结果数组传递给例如立即调用的箭头函数,其中对函数的参数和其余参数使用解构。 这是因为 OP 希望以不同于其余数据值的方式处理lineNumber (或NUMBER )相关值。 这些是函数的restData数组的一部分,将根据 OP 的固定数字字符串值进行映射。 通过使用Spread Syntax ,实数类型和固定数字字符串值数组这两个部分都作为一个数组返回。

有第二个较短的赋值,它利用了正则表达式结果的groups属性。 这种方法的原因并不完全返回 OP 的请求值。 尽管如此,还是提供了代码以显示如何直接从groups属性中解构这些值(因为使用了具有命名捕获组功能的正则表达式)。

 const regXDrillData = /NUMBER\:=(?<number>[^,]+),.*?X:=(?<x>[^,]+),.*?Y:=(?<y>[^,]+),.*?Z:=(?<z>[^,]+),.*?A:=(?<a>[^,]+),.*?B:=(?<b>[^,]+)/g; const textString = `DRILL(NUMBER:=20,NAME:='4',PN:=1,X:=10.1,Y:=73.344,Z:=0,A:=-1.435,B:=1.045,M1:=1,M2:=2,M3:=3,M4:=4,M5:=1,S1:=10.5,S2:=2.1,S3:=1.2,S4:=2,S5:=2.4,RS1:=1,RS2:=2);`; // - processed values via an immediately // invoked arrow function which gets // passed the result array of `matchAll`. let [ lineNumber, x, y, z, a, b, ] = (([match, number, ...restData]) => [ Number(number), ...restData.map(value => Number(value).toFixed(1) ) ])(...textString.matchAll(regXDrillData)); console.log( `processed values via an immediately invoked arrow function which gets passed the result array of 'matchAll'...`, {lineNumber, x, y, z, a, b }, ); // - straightforward as unprocessed // string values directly from // the `groups` result. ({ number: lineNumber, x, y, z, a, b, } = regXDrillData.exec(textString)?.groups?? {}); console.log( `straightforward as unprocessed string values directly from the 'groups' result...`, {lineNumber, x, y, z, a, b }, );
 .as-console-wrapper { min-height: 100%;important: top; 0; }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM