Есть ли лучший способ извлечь информацию из строки?

Допустим, у меня есть массив строк, и мне нужна конкретная информация о них, что будет простым способом сделать это?

Предположим, что массив был

let infoArr = [
  "1 Ben Howard 12/16/1988 apple",
  "2 James Smith 1/10/1999 orange",
  "3 Andy Bloss 10/25/1956 apple",
  "4 Carrie Walters 8/20/1975 peach",
  "5 Doug Jones 11/10/1975 peach"
];

Допустим, я хотел, чтобы дата была извлечена и сохранена в другом массиве, ну, я мог бы сделать такую функцию

function extractDates(arr){
  let dateRegex = /(\d{1,2}\/){2}\d{4}/g, dates = "";
  let dateArr = [];
  for(let i = 0; i<arr.length; i++){
    dates = /(\d{1,2}\/){2}\d{4}/g.exec(arr[i])
    dates.pop();
    dateArr.push(dates);
  }
  return dateArr.flat();
}

Хотя это работает, это неуклюже и требует, чтобы я pop(), потому что это возвратит массив массивов, то есть: ["16.12.1988", "16/"], плюс мне нужно впоследствии вызвать flat.

Другим вариантом будет подстрока строк с заданной позицией, где мне нужно знать шаблон регулярных выражений.

function extractDates2(arr){
  let dates = [];
  for(let i = 0; i<arr.length; i++){
    let begin = regexIndexOf(arr[i], /(\d{1,2}\/){2}\d{4}/g);
    let end = regexIndexOf(arr[i], /[0-9] /g, begin) + 1;
       dates.push(arr[i].substring(begin, end));
  }
  return dates;
 }

И, конечно, есть функция regexIndexOf

function regexIndexOf(str, regex, start = 0){
  let indexOf = str.substring(start).search(regex);
  indexOf = (indexOf >= 0) ? (indexOf + start) : -1;
  return indexOf;
}

Опять же, эта функция также работает, но кажется, что нужно извлечь что-то простое. Есть ли более простой способ извлечь данные в массив?

Ответ 1

Одним из вариантов было бы объединить строки сепаратором, который не будет соответствовать, как ,, то просто выполнить глобальный матч, чтобы получить массив дат из него:

let infoArr = [
  "1 Ben Howard 12/16/1988 apple",
  "2 James Smith 1/10/1999 orange",
  "3 Andy Bloss 10/25/1956 apple",
  "4 Carrie Walters 8/20/1975 peach",
  "5 Doug Jones 11/10/1975 peach"
];
const result = infoArr
  .join(',')
  .match(/(\d{1,2}\/){2}\d{4}/g);
console.log(result);

Ответ 2

Одним из подходов может быть использование map() над элементами массива с применением соответствия для каждого элемента и, наконец, вызовом flat() для получения желаемого результата:

let infoArr = [
  "1 Ben Howard 12/16/1988 apple",
  "2 James Smith 1/10/1999 orange",
  "3 Andy Bloss 10/25/1956 apple",
  "4 Carrie Walters 8/20/1975 peach",
  "5 Doug Jones 11/10/1975 peach"
];

const result = infoArr.map(o => o.match(/(\d{1,2}\/){2}\d{4}/g)).flat();

console.log(result);

Ответ 3

Хотя это работает, это неуклюже и требует pop() потому что он будет возвращать массив массивов, то есть: ["12/16/1988", "16/"], плюс мне нужно впоследствии вызывать flat.

Метод regex exec всегда имеет свое совпадение в свойстве 0 (при условии, что оно совпадает вообще), вы можете просто получить к нему доступ и передать его в свой массив:

let infoArr = [
  "1 Ben Howard 12/16/1988 apple",
  "2 James Smith 1/10/1999 orange",
  "3 Andy Bloss 10/25/1956 apple",
  "4 Carrie Walters 8/20/1975 peach",
  "5 Doug Jones 11/10/1975 peach"
];

function extractDates(arr){
  const dateRegex = /(\d{1,2}\/){2}\d{4}/g;
  const dateArr = [];
  for (const str of arr){
    const date = /(\d{1,2}\/){2}\d{4}/g.exec(str);
    dateArr.push(date[0]);
  }
  return dateArr;
}

console.log(extractDates(infoArr));

Ответ 4

Вы можете использовать reduce() вместо циклов для сопряжения кода. Просто будьте осторожны, чтобы сохранить null в массиве, если нет совпадений.

let infoArr = [
    "1 Ben Howard 12/16/1988 apple",
    "2 James Smith 1/10/1999 orange",
    "3 Andy Bloss 10/25/1956 apple",
    "4 Carrie Walters 8/20/1975 peach",
    "5 Doug Jones 11/10/1975 peach"
  ];
  
let regex = /(\d{1,2}\/){2}\d{4}/g
let dates =  infoArr.reduce((arr, s) => arr.concat(s.match(regex) || []) , [])
console.log(dates)