Validate a string that only contains a single occurrence of some specific substring

Viewed 33

I'm trying to match entire strings that:

  1. Only has one occurrence of the specified word
  2. Allows anything before and after the occurrence, except specified word

The ideal results are as such:

{{REPLACE}}. // Valid
{{REPLACE}} {{REPLACE}}. // Invalid
{{REPLACE}}{{REPLACE}}. // Invalid
Text here {{REPLACE}}. More text here. // Valid
{{REPLACE}} text here {{REPLACE}}. More text here // Invalid

The closest I've gotten to is

{{REPLACE}}. // Valid
{{REPLACE}} {{REPLACE}}. // Valid
{{REPLACE}}{{REPLACE}}. // Invalid
Text here {{REPLACE}}. More text here. // Valid
{{REPLACE}} text here {{REPLACE}}. More text here // Valid

Using /(?<!({{REPLACE}}))({{REPLACE}}){1}(?!({{REPLACE}}))/

1 Answers

You can use

/^(?!(?:.*?{{REPLACE}}){2}).*?{{REPLACE}}/             // If no line breaks are present
/^(?!(?:[\w\W]*?{{REPLACE}}){2})[\w\W]*?{{REPLACE}}/   // If there can be line breaks

See the regex demo

Details:

  • ^ - start of string
  • (?!(?:.*?{{REPLACE}}){2}) - a negative lookahead that fails the match if, immediately to the right of the current location, there are two sequences of any zero or more chars other than line break chars as few as possible and then {{REPLACE}} substring
  • .*? - any zero or more chars other than line break chars as few as possible
  • {{REPLACE}} - {{REPLACE}} substring (or some specific pattern).

If you need to match whole lines like this, you should add .* to the first pattern and use gm flags:

/^(?!(?:.*?{{REPLACE}}){2}).*?{{REPLACE}}.*/gm

See JavaScript demo:

const texts = ['{{REPLACE}}.', '{{REPLACE}} {{REPLACE}}.', '{{REPLACE}}{{REPLACE}}.', 'Text here {{REPLACE}}. More text here.','{{REPLACE}} text here {{REPLACE}}. More text here'];
const regex = /^(?!(?:.*?{{REPLACE}}){2}).*?{{REPLACE}}/;
texts.forEach( x =>
  console.log(x, '=>', regex.test(x))
)

Related