# How can one represent a string pattern with prohibited substrings?

Say I have the following string: "<hello>something WRONG</hello><hello>something else</hello>"

I am trying to find code that works like the following:

StringCases[string,
"<hello>" ~~
something : StringPatternThatDoesntContainString["WRONG"] ~~
"</hello>" :> something]


I'm trying to find all the string between hello tags that don't contain the "WRONG" string.

-

str = "<hello>something</hello><hello>something</hello><hello>something WRONG</hello>";
StringCases[str,
"<hello>" ~~ Shortest[st__] ~~ "</hello>" /; StringFreeQ[st, "WRONG"] :> st]

{"something", "something"}


(With hat tip to Alexey Popkov for adding robustness via Shortest).

-
Your current solution fails with for example str = "<hello>something</hello><hello>something2</hello>";. You should replace st__ with Shortest[st__] to avoid this: by default string patterns are greedy (in contrast with the usual patterns). – Alexey Popkov Mar 28 at 12:11
@Alexey. Agreed. I will modify it. – march Mar 28 at 15:36
I have taken the liberty to update the output in your answer (which you forgot to update) and to add more representative str for testing the solution. I hope you don't mind. – Alexey Popkov Mar 28 at 16:06
@AlexeyPopkov. Yeah! No problem. I hadn't had my morning coffee yet. – march Mar 28 at 16:07

A solution using regular expression with Negative Lookahead (?!regex) Before the Match:

string = "<hello>something WRONG</hello><hello>something else</hello><hello>WRONG</hello>";

StringCases[string,
"<hello>" ~~ st : RegularExpression["(?:(?!WRONG).)*?"] ~~ "</hello>" :> st]

{"something else"}


An alternative solution using pure regexes (should be more efficient):

StringCases[string, RegularExpression["(?ms)<hello>((?:(?!WRONG).)*?)</hello>"] :> "$1"]  {"something else"}  A detailed description of this method can be found here. ## UPDATE Performance comparison of the three methods including the improved solution by march (timings for version 10.4 on Win7 x64): string = "<hello>something WRONG</hello><hello>something</hello><hello>something \ else</hello><hello>WRONG</hello>"; stringBig = StringJoin@ConstantArray[string, 1*^3]; First@AbsoluteTiming[ r1 = StringCases[stringBig, "<hello>" ~~ Shortest[st__] ~~ "</hello>" /; StringFreeQ[st, "WRONG"] :> st]] First@AbsoluteTiming[ r2 = StringCases[stringBig, "<hello>" ~~ st : RegularExpression["(?:(?!WRONG).)*?"] ~~ "</hello>" :> st]] First@AbsoluteTiming[ r3 = StringCases[stringBig, RegularExpression["(?ms)<hello>((?:(?!WRONG).)*?)</hello>"] :> "$1"]]
r1 === r2 === r3

326.007

0.00696272

0.00824213

True


As one can see, the StringExpression (~~) solution with Condition (/;) is more than 4 orders of magnitude slower than StringExpression without it. What is unexpected is that pure RegularExpression solution is slower than StringExpression without Condition. This topic was discussed before but an explanation was not found.

-
"negative lookahead" - so, "look behind"? ;) – J. M. Mar 28 at 3:50
Ah, "negative" as in "should not match". Okay then. – J. M. Mar 28 at 4:39