-1

I have a text, and a "marker" (regexp = "error"). I can find position of the "marker", but base target is number of article, that stands before the "marker". In short, I need to find number(s) with regexp = /\d{2}\\/\d{2}\\/\d{4}/). Need to find 09/09/4567 in my case. How can i make it?

text = "harum voluptatibus laboriosam blanditiis similique commodi labore 09/09/4567 repellat error quasi animi nostrum magnam, ab asperiores unde porro! ipsum dolor sit amet, consectetur adipisicing elit. Velit, delectus esse aperiam quod aliquid sunt iure ducimus. Nesciunt eveniet, possimus 09/09/4568 adipisci accusamus reiciendis , quos pariatur, sapiente rem quaerat cumque."
text.match("error");
Fraction
  • 6,401
  • 3
  • 15
  • 34
piperpiper
  • 11
  • 1
  • Looks like you need something like `/\d{2}\/\d{2}\/\d{4}(?=(?:(?!\d{2}\/\d{2}\/\d{4})[^])*?error)/g`, see [demo](https://regex101.com/r/p2Oc1E/1). – Wiktor Stribiżew Aug 04 '19 at 10:46

2 Answers2

1

In a comment I asked:

What two results do you want from "one 01/01/1111 two error 02/02/2222 three four 03/03/3333 five error"? Do you want 01/01/1111 and 02/02/2222, or 01/01/1111 and 03/03/3333? (Note that 'error' only appears twice in that string.)

and you answered

i need [01/01/1111, 03/03/3333]

I can't do that with a single regular expression. I tried /.*(\d\d\/\d\d\/\d\d\d\d).*?error/ but that gets just 03/03/3333.

Doing it by finding error and then looking for the nearest digits to it works:

const text = "one 01/01/1111 two error 02/02/2222 three four 03/03/3333 five error blah blah";
const rexError = /error/g;
const rexDigits = /.*(\d\d\/\d\d\/\d\d\d\d)/;
let result;
let last = 0;
while (result = rexError.exec(text)) {
  result = rexDigits.exec(text.substring(last, result.index))
  if (result) {
    console.log(result[1]);
  }
}

The .* at the beginning is what skips the first set of digits and lets the match reach the last set instead.

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
1

You may use

/\d{2}\/\d{2}\/\d{4}(?=(?:(?!\d{2}\/\d{2}\/\d{4})[^])*?error)/g

See the regex demo.

To match the pattern as whole word, add word boundaries:

/\b\d{2}\/\d{2}\/\d{4}\b(?=(?:(?!\b\d{2}\/\d{2}\/\d{4}\b)[^])*?\berror\b)/g

Details

  • \d{2}\/\d{2}\/\d{4} - two digits, /, two digits, /, four digits
  • (?=(?:(?!\d{2}\/\d{2}\/\d{4})[^])*?error) - immediately to the right from the current location, there should be a match of
    • (?:(?!\d{2}\/\d{2}\/\d{4})[^])*?- any char ([^], you may also use [\s\S]), 0 or more repetitions but as few as possible (*?), that does not start the \d{2}\/\d{2}\/\d{4} pattern described above
    • error - an error substring.

JS demo:

var text = "harum voluptatibus laboriosam blanditiis similique commodi" + 
 "labore 09/09/4567 repellat error quasi animi nostrum magnam, ab asperiores unde porro! "+
 "ipsum dolor sit amet, consectetur adipisicing elit. Velit, delectus esse aperiam quod " +
 "aliquid sunt iure ducimus. Nesciunt eveniet, possimus 09/09/4568 adipisci accusamus " + 
 "reiciendis , quos pariatur, sapiente rem quaerat cumque.\n" +
 "one 01/01/1111 two error 02/02/2222 three four 03/03/3333 five error";
var rx = /\d{2}\/\d{2}\/\d{4}(?=(?:(?!\d{2}\/\d{2}\/\d{4})[^])*?error)/g;
console.log(text.match(rx));
Wiktor Stribiżew
  • 484,719
  • 26
  • 302
  • 397
  • 1
    @T.J.Crowder This is based on a [tempered greedy token](https://stackoverflow.com/a/37343088/3832970). – Wiktor Stribiżew Feb 07 '20 at 12:03
  • Thanks! I have to admit that when I was looking at the expression, I missed the negative lookahead entirely. (I'm under the weather.) Makes sense now -- and is very cool. – T.J. Crowder Feb 07 '20 at 12:05