【问题标题】:How to match on all 5 digit numbers but skip the first match如何匹配所有 5 位数字但跳过第一个匹配
【发布时间】:2019-04-22 23:35:17
【问题描述】:

我正在尝试提取与员工编号相关的文件名中的所有 5 位数字。我遇到的问题是文件名中的前 5 位数字与作业编号有关。我需要跳过第一个匹配项,然后继续匹配所有 5 位数字

var str = "01_12345_02_02_2019_12347_67890_10112_13141";
var empRegex = /(\d{5})/g;
var empNumbers;
empNumbers = str.match(empRegex).toString();
console.log(empNumbers);

我需要"12347, 67890, 10112, 13141"

我收到了"12345, 12347, 67890, 10112, 13141",但找不到任何跳过第一个匹配项的内容。

【问题讨论】:

  • 您当前的正则表达式不匹配任何内容,因为您在 str 中没有任何 ds
  • 我只是像这样设置它作为一个例子。在这种情况下,“str”实际上是一个文件名,它被传递给一个函数来收集我所追求的员工编号。在这种情况下我需要使用正则表达式,因为有时文件名上可能有 10 个员工编号,而在其他情况下只有 1 或 2 个。

标签: javascript arrays regex string


【解决方案1】:

解决方案:

您的 RegEx 中有错字。应该是\d{5} 而不是d{5}

其次,要删除第一个匹配的元素,您只需将数组添加到 shift 即可。 Array.prototype.shift

请务必注意,当您使用 shift 时,shift 的返回值将是被删除的元素,不是新的或更改的数组。这就是为什么您必须将变量分配给原始数组的原因,分配后在数组上完成 shift 方法。

简单地说,你必须这样做:

(empNumbers = str.match(empRegex)).shift(); 

不是这个:

 empNumbers = str.match(empRegex).shift();

由于shift 将更改数组,因此您最终得到的是array 减去第一个匹配的元素。

代码片段:

var str = "01_12345_02_02_2019_12347_67890_10112_13141";
var empRegex = /(\d{5})/g;
var empNumbers;
(empNumbers = str.match(empRegex)).shift();
console.log(empNumbers);

或者:

一个函数:

如果您发现这是您经常要做的事情,那么创建一个为您执行此操作的函数可能符合您的最佳利益。在这种情况下,最好使用这样的东西:

var str = "01_12345_02_02_2019_12347_67890_10112_13141", empRegex = /(\d{5})/g;

function matchExceptFirst(str, RE) {
let matches = str.match(RE); 
matches.shift();
return matches;
}

var empnumbers = matchExceptFirst(str, empRegex);
console.log(empnumbers);

纯函数式方法:

还值得指出的是,如果您希望使用 Functional Paradigm,其中所有内存源都应被视为不可变且不更改上述解决方案,其中您对 Array 进行变异将失败此范例。

为了避免改变数据并返回一个新数组来替换旧数组,您可以使用Array(Array.prototype.filter) 的filter 方法,并通过将索引值转换为布尔值作为谓词进行过滤。这将删除第一个元素,因为0 被认为是falsy,但其余元素将被放置在一个新数组中并返回。

   let excludeFirstMatch = (str, re) => str.match(re).filter((_,i) => (i));

    var str = "01_12345_02_02_2019_12347_67890_10112_13141", empRegex = /(\d{5})/g;
   
   
   let excludeFirstMatch = (str, re) => str.match(re).filter((_,i) => (i));
    

   console.log( 
   excludeFirstMatch(str, empRegex) 
   );

编辑:正如@UlysseBN 指出的,您也可以使用slice,它更快并且还返回一个新数组。

var str = "01_12345_02_02_2019_12347_67890_10112_13141", empRegex = /(\d{5})/g;
   
   
   let excludeFirstMatch = (str, re, len = str.length) => str.match(re).slice(1, len);
    

   console.log( 
   excludeFirstMatch(str, empRegex) 
   );

【讨论】:

  • 对于您的纯功能方法,我真的不明白您为什么使用过滤器而不是切片。恕我直言,对于此类任务, slice 设计得更好,更易于理解。而且我猜也更快。虽然我还没有运行测试。
  • @UlysseBN 我继续使用slice 为答案提供了更多信息。你是对的 - 它让我忘记了,因为我习惯于将 mapfilter 等视为纯数组方法。无论哪种方式,它都会提供相同的结果。感谢您的评论!
  • 您不必费心,因为我已经写了as an answer...但是,您给出的转变解释非常简洁:)
【解决方案2】:

How to match on all 5 digit numbers but skip the first match

这是一种方式:

var str = "01_12345_02_02_2019_12347_67890_10112_13141";
var empRegex = /(?:^.*?\d{5}.*?)?(\d{5})/g;
var empNumbers = [];
var item;

while (item = empRegex.exec( str ))
    empNumbers.push(item[1]);

// ---------
console.log(empNumbers);

【讨论】:

    【解决方案3】:

    使用shift():

     
    
    var str = "01_12345_02_02_2019_12347_67890_10112_13141";
    var empRegex = /(\d{5})/g;
    var empNumbers = str.match(empRegex);
    empNumbers.shift();
    empNumbers = empNumbers.toString();
    console.log(empNumbers);

    【讨论】:

      【解决方案4】:

      您可以在正则表达式匹配后使用array.slice

      var str = "01_12345_02_02_2019_12347_67890_10112_13141";
      var empRegex = /(\d{5})/g;
      var empNumbers;
      empNumbers = str.match(empRegex).slice(1).toString();
      //                              ---------
      console.log(empNumbers);

      如果您知道此字符串的格式永远不会改变,另一种方法是根本不使用正则表达式

      var str = "01_12345_02_02_2019_12347_67890_10112_13141";
      var empNumbers = str.split('_').slice(-4).toString();
      console.log(empNumbers);

      有些人在遇到问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。

      Coding Horror's blog

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-18
        • 2011-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-13
        • 2021-08-30
        • 2023-03-29
        相关资源
        最近更新 更多