# Alternative to Except in StringExpression when using StringMatchQ

According to this answer and the documentation for StringExpression, Except can only be used in StringExpression for classes of characters or positions in strings. The referenced answer suggests using StringFreeQ in place of StringMatchQ. However, sometimes, this is not possible, if the pattern is one of many being passed to a function, like in the following situation

patt1 = WordCharacter..;
patt2 = "pattern";
patt3 = (*Some complicated StringExpression*);
... (*more patterns*)
pattn = (*Everything except patt3*)

f[patt_, str_] := If[StringMatchQ[str, patt], (*stuff*), (*other stuff*)]


One possibility is to use

pattn = x: __ /; !StringMatchQ[x, patt3]


This seems repetitive and it could get verbose if repeated, but isn't too bad. However, my intuition is that there should be a better way. Is there?

-

## 2 Answers

This code turns f[ ___ , Except[ _RegularExpression ] , ___ ] into !f[ ___ , RegularExpression, ___ ] if f begins with String. It would work for StringFreeQ and StringMatchQ but you would have to adjust it for others such as StringCases.

Unprotect[Except];
Except /:
symbol_[head___, Verbatim[Except][re_RegularExpression], tail___] /;
StringMatchQ[SymbolName[symbol], "String" ~~ __] := ! symbol[head, re, tail]
Protect[Except];

regex = RegularExpression@"[[:alnum:]]+@[[:alnum:]]+\\.[[:alnum:]]{2,}";

StringMatchQ["test@example.com", regex]


True

StringMatchQ["test@example.com", Except@regex]


False

StringMatchQ["not.an.email", Except@regex]


True

-
Very interesting ! Bending Mathematica to my will (like a good lawyer the jury): How can I bring it back to standard behaviour later? –  eldo Jun 2 '14 at 20:25
Does this (with minor alteration) support StringExpression as well? –  Daniel Jun 2 '14 at 20:25
@Daniel Yup. Right now it will catch any symbol beginning with String. You could make it behave differently depending on the exact symbol, or more specific patterns. –  mfvonh Jun 2 '14 at 20:30
@eldo Have a look at Information[ Except ] in this example; you will see the extra definitions at the bottom. Since it is a system symbol, you can do Unprotect[Except];ClearAll[Except];Protect[Except]; to restore base definitions. –  mfvonh Jun 2 '14 at 21:09
@Daniel Alternatively, you could attach this rule to your function (here f) (instead of String...). So you could specify: any time RegularExpression is passed to f then do ... –  mfvonh Jun 2 '14 at 21:13

Do you want to achieve something like this?

Clear[patt1, patt2]
patt1 := "__~~WordCharacter"
patt2 := "pattern"

ClearAll@f
f[patt_ /; patt == patt1, str_] := StringMatchQ[str, ToExpression@patt]
f[patt_ /; patt == patt2, str_] := Not@StringFreeQ[str, patt]
f[patt_, str_] := str (* or whatever you want *)

-
That's a possible solution, but it require at least two function definitions, and requires adding every new pattern to one or the other. –  Daniel Jun 2 '14 at 19:19
@Daniel -Yes, that's right. An alternative would be to define "f" only once and then use a "Switch"-statement. But some of the experts here prefer the "verbose" solution. Also, you don't need to define "patt1" & "patt2" beforehand. You could directly write: "f[patt_ /; patt == "pattern", str_] := ..." –  eldo Jun 2 '14 at 19:24