2
$\begingroup$

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?

$\endgroup$

2 Answers 2

2
$\begingroup$

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

$\endgroup$
6
  • $\begingroup$ Very interesting ! Bending Mathematica to my will (like a good lawyer the jury): How can I bring it back to standard behaviour later? $\endgroup$
    – eldo
    Jun 2, 2014 at 20:25
  • $\begingroup$ Does this (with minor alteration) support StringExpression as well? $\endgroup$
    – Daniel
    Jun 2, 2014 at 20:25
  • $\begingroup$ @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. $\endgroup$
    – mfvonh
    Jun 2, 2014 at 20:30
  • $\begingroup$ @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. $\endgroup$
    – mfvonh
    Jun 2, 2014 at 21:09
  • $\begingroup$ @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 ... $\endgroup$
    – mfvonh
    Jun 2, 2014 at 21:13
1
$\begingroup$

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 *)
$\endgroup$
2
  • $\begingroup$ That's a possible solution, but it require at least two function definitions, and requires adding every new pattern to one or the other. $\endgroup$
    – Daniel
    Jun 2, 2014 at 19:19
  • $\begingroup$ @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_] := ..." $\endgroup$
    – eldo
    Jun 2, 2014 at 19:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.