7
$\begingroup$

Bug introduced in 5 or earlier and persists through 10.4.1


Anyone knows why

StringMatchQ["x", Except[{"1", "2"}]]

StringMatchQ["x", Except[{"*"}]]

StringMatchQ["x", {"1", "*"}]   (* without Except *) 

all work as expected, but

StringMatchQ["x", Except[{"1", "*"}]]

throws the following error:

StringExpression::invld: Element Except[{1,*}] is not a valid string 
   or pattern element in StringExpression[Except[{1,*}]]. >>
$\endgroup$
  • $\begingroup$ Related: mathematica.stackexchange.com/a/39527/57 $\endgroup$ – Sjoerd C. de Vries Apr 8 '15 at 19:32
  • $\begingroup$ Doesn't your own answer imply that this usage is invalid? $\endgroup$ – Mr.Wizard Apr 9 '15 at 1:06
  • $\begingroup$ @mr.wizard that answer implies that the pattern (Except [p]) can only stand for a single character, not that the pattern element itself (p) must be a single character. The first example seems to support this. $\endgroup$ – Sjoerd C. de Vries Apr 9 '15 at 6:14
  • $\begingroup$ @SjoerdC.deVries I have read this but I think that even if we accept that implicit documentation statement we still have a couple of bugs here... $\endgroup$ – Alexey Popkov Jun 14 '16 at 18:50
5
$\begingroup$

I don't think that StringMatchQ["x", Except[{"*"}]] works as expected as well as StringMatchQ["x", Except["*"]]:

StringMatchQ["x", Except[{"*"}]]
StringMatchQ["x", Except["*"]]
True

True

The string pattern "*" is an abbreviated string pattern consisted from the only metacharacter * which corresponds to zero or more characters according to the first point under the "Details and Options" section of StringMatchQ. So by the definition the pattern Except["*"] shouldn't give a match at all because it means negation of literally everything. Also for matching verbatim "*" one must escape this metacharacter with double backslash "\\*" (the reference is the same). So current behavior is a bug.

Note also that escaping with single backslash is meant for Mathematica's internal metacharacters like < and > (and obviously for more common n, t and r etc. but with another counting by StringLength) as described in this answer by John Fultz:

The modern Mathematica notebook format (introduced in 1996) was always made to be interpreted properly as a Mathematica expression should you call Get[] on it from the kernel. So this syntax was standardized, and is still used today. Now, the kernel simply ignores the \< \> delimiters as you can see below:

In[1]:== StringLength["\<x\>"]
Out[1]== 1

The following demonstrates a possible bug (for the string "\*" length must be 2 because * isn't an internal metacharacter of Mathematica and it needs not be escaped inside of an ordinary string):

StringLength["*"]
StringLength["\*"]
1

1
StringLength["\x"]

Syntax::stresc: Unknown string escape \x.

2

The following is a set of examples of the expected behavior (observed with version 10.4.1):

StringMatchQ["", "*"]
StringMatchQ["", Except["*"]]
True

False
StringMatchQ["xy", {"*"}]
StringMatchQ["xy", "*"]
True

True
StringMatchQ["*", Except[{"*"}]]
StringMatchQ["*", Except["*"]]
StringMatchQ["xy", Except["*"]]
False

False

False
StringMatchQ["x", "@"]
True
StringMatchQ["x", {"\\*"}]
StringMatchQ["x", "\\*"]    
StringMatchQ["*", "\\*"]
False

False

True

The following is a set of examples of wrong behavior of Except with metacharacters:

StringMatchQ["x", Except[{"\\*"}]] (* metacharacter is correctly escaped *)
StringMatchQ["x", Except["\\*"]] (* metacharacter is correctly escaped *)

StringExpression::invld: Element Except[{\*}] is not a valid string or pattern element in Except[{\*}]. >>

StringMatchQ["x", Except[{"\\*"}]]

StringExpression::invld: Element Except[\*] is not a valid string or pattern element in Except[\*]. >>

StringMatchQ["x", Except["\\*"]]
StringMatchQ["x", Except["\*"]] (* metacharacter is wrongly escaped *)
StringMatchQ["*", Except["\*"]] (* metacharacter is wrongly escaped *)
True

True
StringMatchQ["x", Except["@"]]

StringExpression::invld: Element Except[@] is not a valid string or pattern element in Except[@]. >>

StringMatchQ["x", Except["@"]]

And here is an example of wrong (but consistent) behavior of StringMatchQ both with Except and without it:

StringMatchQ["\*", Except["\*"]] (* metacharacter is wrongly escaped *)
StringMatchQ["\*", "\*"] (* metacharacter is wrongly escaped *)
False

True

In addition:

StringMatchQ["*", Except["\*"]]
True

Update

I've found an old MathGroup discussion on this topic from where I learned that StringCases and StringPosition don't have the abbreviated string pattern option, and that Verbatim forces StringMatchQ to match two strings literally: StringMatchQ["\\*", Verbatim["\\*"]] returns True.

$\endgroup$
  • $\begingroup$ It's a bit long ago, so I don't recall what made me write "work as expected". Perhaps I was just looking at the generation of an error message. Anyway, it indeed looks like there is a bug in Mathematica's treatment of meta-characters. Nice treatment of the issue (+1). $\endgroup$ – Sjoerd C. de Vries Jun 15 '16 at 21:11

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.