1

I tried negative lookahead but not working. I am doing a mistake and I don't know where.

I have a date pattern and want to match everything except that pattern, like below.

Hey how 30.01.2019 are you 23.05.2020 I am fine. ==> (want to match bold areas)

my date pattern is that = ^([0-2][0-9]|(3)[0-1])(\.)(((0)[0-9])|((1)[0-2]))(\.)(\d{4}|\d{2})$

Thanks in advance.

Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
Emil Mammadov
  • 380
  • 4
  • 20
  • do numbers and dots ever appear in the desired content? if not `([^0-9\.])` will work as a base regex. You can modify with quantifiers to, e.g., `([^0-9\.])+`. Probs not what you want, but maybe? Here's a version with repeating groups ``((?:[^0-9\.])+)` – varontron Jan 24 '20 at 06:26
  • @varontron numbers and dots appears in the text. – Emil Mammadov Jan 24 '20 at 06:27
  • A good solution with a plain pattern would be possible in PHP and a few others, but not in JS, I think. What are you trying to do with the matches? Do you want to replace them with something, or get an array of match strings? – CertainPerformance Jan 24 '20 at 06:31
  • I want to replace where date not appears – Emil Mammadov Jan 24 '20 at 06:34
  • On occasion, I've run into this same scenario and each time I found it was just easier to look for all that does match the unwanted, then remove it and I'm left with what I initially wanted. You might want to consider going that route. Will make your logic a heck of a lot easier to understand if you ever need to revisit it. – David Tran Jan 24 '20 at 06:45
  • `(?:[0-2][0-9]|3[0-1])\.(?:0[0-9]|1[0-2])\.(?:\d{4}|\d{2})` will match all dates in the line. You could combine this with substitution function, – varontron Jan 24 '20 at 06:46
  • 1
    Turn all capturing groups into non-capturing and split with the regex. If string is needed as a result, just join the chunks back – Wiktor Stribiżew Jan 24 '20 at 08:34

2 Answers2

1

You can use a pattern which matches either the date pattern or anything else, up until the start of a date pattern (or the end of the string). Then use a replacer function. If the match is the same format as the date, replace with the entire match (thereby leaving the string unchanged there). Otherwise, replace with whatever you need.

const str = 'Hey how 30.01.2019 are you 23.05.2020 I am fine.';
const datePatternStr = String.raw`(?:[0-2]\d|3[01])\.(?:0\d|1[0-2])\.(?:\d{4}|\d{2})`;
const datePattern = new RegExp(datePatternStr);
const result = str.replace(
  new RegExp(`${datePatternStr}|.+?(?=$|${datePatternStr})`, 'g'),
  (match) => {
    if (datePattern.test(match)) return match;
    return 'foo bar';
  }
);
console.log(result);

The constructed pattern:

${datePatternStr}|.+?(?=$|${datePatternStr})

means:

  • ${datePatternStr} - Match the date pattern, or:
  • .+?(?=$|${datePatternStr}) - Match:
    • .+? One or more characters, as few as possible, up until lookahead matches:
      • $ either the end of the string, or
      • datePatternStr

Note that you can trim your original pattern down to:

(?:[0-2]\d|3[01])\.(?:0\d|1[0-2])\.(?:\d{4}|\d{2})

(only use groups when they're required for the logic you need, \d can be used instead of [0-9], and only use capturing groups when non-capturing groups won't suffice)

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

An one liner for you:

var string = "Hey how 30.01.2019 are you 23.05.2020 I am fine.";
var results = string.replace(/\d{1,2}\.\d{1,2}\.\d{4}/g,'%|%').split('%|%');
console.log(results);

Description: Replaced all the dates with %|% and after that splitted the string with %|%.

Taha Paksu
  • 15,371
  • 2
  • 44
  • 78