2

I am trying to come up with a PHP regex that matches any strings except strings which have two open curly braces at the start as well as two closed curly braces at the end.

So anything other than specifically:

{{someString}}

The string can have no braces, as long as it's not 2 open and 2 closed at the start and end of the string.

So far my best attempt has been

^(?!{{).+(?!}})$

But I later realized that this doesn't match a string like {{x (because it starts with {{); I do want that string to match, just not something like {{x}}.

How can I fix this?

ruakh
  • 156,364
  • 23
  • 244
  • 282
Ravi
  • 133
  • 10
  • The examples you show doesn't ALL start with '{{' and doesn't ALL end with '}}' – Poul Bak Aug 21 '18 at 23:31
  • didn't get that. – Ravi Aug 21 '18 at 23:36
  • Are you sure your last paragraph regarding "should match" is consistent with your first sentence? That is, aren't you seeking to match the second list and fail the first list? In other words, why not use `^{{.*}}$` which matches the second list (e.g. `{{...}}` etc) and fails on the first and filter anything matching that rather than the opposite? Also, what's your PHP code like or what are you [trying to achieve](https://en.wikipedia.org/wiki/XY_problem)? – ggorlen Aug 21 '18 at 23:39
  • sorry for the ambiguous wording 'filters out'. I meant 'doesn't match'. The last paragraph is what i want – Ravi Aug 21 '18 at 23:42
  • 1
    Curly braces are special characters in regex. Maybe you should try escaping them – Roberto Maldonado Aug 21 '18 at 23:43
  • $validations['parameter_custom_value'] = array('required', 'regex:/^(?!{{).+(?!}})$/'); – Ravi Aug 21 '18 at 23:46
  • "*I want only string that BOTH start with {{ and end with }} So, string that it should match are {{...}*" these two sentences contradict each other, as your example has 2 braces at the start and end, then your examples sometimes only have one at the start or end. Your final paragraph is contradictory too - "*string that should fail are {{...}}*" this string is exactly like your initial example. Can you clarify how many braces need to be on each end, and how many don't? – James Aug 21 '18 at 23:51
  • @James thanks for pointing my mistake. To clarify, I will accept any string that is NOT like {{..}} – Ravi Aug 21 '18 at 23:58
  • So would you accept a string without any braces? – James Aug 22 '18 at 00:04
  • yes, I will accept strings without braces also, like ABC – Ravi Aug 22 '18 at 00:04
  • `'~^(?!{{.*}}$).*$~s'` – Wiktor Stribiżew Aug 22 '18 at 07:37

2 Answers2

1

You can write:

^(?!{{.*}}$)

to match anything that's not matched by

^{{.*}}$
ruakh
  • 156,364
  • 23
  • 244
  • 282
  • 1
    doesn't match {{a} – Ravi Aug 22 '18 at 00:21
  • @Ravi: Why not? – ruakh Aug 22 '18 at 01:34
  • 1
    The problem is there's no capturing group. I think you actually want `^(?!{{.+}})(.*)$` – Nick Aug 22 '18 at 01:42
  • @Nick: Why does there need to be a capturing group? – ruakh Aug 22 '18 at 01:51
  • Otherwise there is nothing to match so no match will be reported. Try removing the capturing group from the regex [here](https://regex101.com/r/4KvuNe/3) and you will see it reports that the regex doesn't match anything. – Nick Aug 22 '18 at 02:00
  • @Nick: Are you saying that the OP doesn't just need the regex to match or not-match (boolean result), but also needs the matched substring to cover the entire string? If so, that doesn't require a capture-group; (s)he can just append `.*`. – ruakh Aug 22 '18 at 02:35
  • My point was that without anything after the negative lookahead, it seems to always return not-match. I agree it doesn't have to be a capture group, it could be just `.*`. – Nick Aug 22 '18 at 02:46
  • @Nick: The problem is that your point is wrong (as is the OP's comment) -- https://regex101.com/r/hA7H6h/1 clearly shows a match at the start of the `{{a}` line -- so I'm trying to find a not-wrong point that you might have meant instead. :-/ – ruakh Aug 22 '18 at 03:48
  • You are right. I missed the mark at the beginning of the string. Sorry for wasting your time. :-( – Nick Aug 22 '18 at 05:07
  • Not sure why this was down voted. I have compensated. – Nick Aug 22 '18 at 05:45
  • Thanks everyone, I think I will go with Nick's answer, ( I added a $ at the end of the negative lookahead group, otherwise it will reject {{abc}}d ) – Ravi Aug 22 '18 at 16:44
0

Just take the problem from the other end...
We know exactly what shouldn't "pass"... And the rule is simple:

{{whatever or nothing between double curly brackets}}

So why not try to match that simple rule and deduct the result?

The string is OK when there is no match!

Paste the code below in PhpFiddle:

<?php
echo "<h1>Strings 0 to 5 should pass and the rest should fail.</h1>";

// Should pass
$string[0] = "test";
$string[1] = "{test";
$string[2] = "test}";
$string[3] = "{test}";
$string[4] = "{{test}";
$string[5] = "{test}}";

// Should fail
$string[6] = "{{test}}";
$string[7] = "{{test}}}";
$string[8] = "{{{test}}";
$string[9] = "{{{test}}}";
$string[10] = "{{}}";

$pattern = "/[\{]{2}.*[\}]{2}/";
for($i=0; $i<sizeof($string);$i++){
    echo $i." - String is: <b>".$string[$i]."</b><br>";
    // --------
    preg_match($pattern,$string[$i],$matches);
    if($matches==null){
        echo "<span class='pass'>That string is ok.</span><br>";
    }else{
        echo "<span class='fail'>That string is NOT ok.</span><br>";
    }
    echo "<br><br>";
}
?>
<style>
    .pass{
        color:green;
    }
    .fail{
        color:red
    }
</style>
Louys Patrice Bessette
  • 27,837
  • 5
  • 32
  • 57
  • Thanks! I tried this blacklisting approach elsewhere. But in this situation since I am forced to use Laravel 5.4's regex validation, I have to go with a whitelisting approach – Ravi Aug 22 '18 at 16:43