Reputation: 5382
I need to be able to replace a string with what would be wrapped in a sort of BBcode style element, but only if that string is not already wrapped in the element.
Example:
The fox runs really fast through Sudan, but also runs really fast through [country]Canada[/country]
Loopping through a list of all the countries I want to replace and wrap in this country brackets I tried this
$replace = preg_replace("#(?<!\[country(.)\])". preq_quote($country) ."(?!\[/country\])#", "[country]{$country}[/country]", $replace);
Expected output:
The fox runs really fast through [country]Sudan[country], but also runs really fast through [country]Canada[/country]
But Im actually getting
Actual output:
The fox runs really fast through [country]Sudan[country], but also runs really fast through [country][country]Canada[/country][/country]
If its already wrapped, I dont want to re-wrap it.
Upvotes: 0
Views: 224
Reputation: 89557
It's easy, you can use the (*SKIP)(*FAIL)
trick to skip all that you want in a string:
$listOfCountries = array('France', 'Soudan', 'Quatar', 'China', 'Zimbabwe');
$pattern '~\[country][^[]+\[/country](*SKIP)(*FAIL)|\b(?i:'
. implode('|', $listOfCountries) . ')\b~';
$result = preg_replace($pattern, '[country]$0[/country]', $text);
(*SKIP)
forbids to retry a substring when the pattern fails later, and (*FAIL)
forces the regex engine to fail.
Note: if you are sure that the list of countries only contains letters and spaces, you don't need to use preg_quote. However if your list contains abbr like R.D.C. ("République Démocratique du Congo"), it is better to use preg_quote. Be careful, if you have abbr in the list \b
will no more work, you must replace it with an other kind of boundary (since the dot is not in \w
), example:(?=\s|[^\PP.])
(a white character or a punctuation character that is not a dot)
Upvotes: 1