# Using Except with strings

Suppose that I have the following sample list, called list:

list = {"bBb", "aAa", "aaa"};


Now suppose I want to select the elements that do not contain the string "A". One way to do this is to use Select with StringMatchQ:

Select[list, ! StringMatchQ[#, ___ ~~ "A" ~~ ___] &]


{"bBb", "aaa"}

(See, for example, this old question.)

But, instead of selecting the elements which do not contain "A", is it possible to use Select with StringMatchQ, but this time selecting all patterns except those that match the pattern ___ ~~ "A" ~~ ___. My thought is to use Except:

Select[list, StringMatchQ[#, Except[___ ~~ "A" ~~ ___]] &]


{}

StringExpression::invld: Element Except[___ ~~ "A" ~~ ___] is not a valid string or pattern element in StringExpression[Except[___ ~~ "A" ~~ ___]]

But I get the error message above. So I looked in the documentation for StringMatchQ. It has the following three general syntax forms:

StringMatchQ["string", patt]
StringMatchQ["string", RegularExpression["regex"]]
StringMatchQ[{s1, s2, ...}, p]


Thinking about the first form, StringMatchQ takes a pattern as its second argument. I know that ___ ~~ "A" ~~ ___ is a pattern, but is Except[___ ~~ "A" ~~ ___] a pattern? According to the documentation for Except, it is. The next question is, is Except[___ ~~ "A" ~~ ___] a string pattern? According to the error message above, it would seem not. (Also, apparently StringMatchQ takes only string patterns as its second argument -- which, of course, is logical.)

So, my overall question is, why does Select[list, StringMatchQ[#, Except[___ ~~ "A" ~~ ___]] &] give an error?

• I've found that Except is generally buggy with strings, which is why I always avoid it (with strings). For instance, compare: StringMatchQ["a", Except["b"]] and StringMatchQ["a", Except["bb"]] – rm -rf Dec 28 '13 at 18:22
• @rm-rf The StringExpression doc says: Except[p] - any character except ones matching p IMHO implying that p can only be a character in this context and not a string. Behavior is therefore documented and not a bug. – Sjoerd C. de Vries Dec 28 '13 at 18:39
• @SjoerdC.deVries Ah, good point. I forgot that StringMatchQ internally calls StringExpression on the second argument. That also explains OP's error then. You should post that as an answer. – rm -rf Dec 28 '13 at 18:45

When applied to string patterns Except only seems to work for string patterns that represent classes of characters or for string patterns that represent positions in strings, e.g.:

Except[{"A" | "B"}]
Except[WordCharacter]
Except[StartOfLine]


If you apply Except to an arbitrary String pattern (i.e., the head is StringExpression), the resulting expression does not seem to be a workable string expression. The documentation does not make this explicitly clear.

An alternate solution is to use StringFreeQ instead of StringMatchQ with Except:

Select[list, StringFreeQ[#, ___ ~~ "A" ~~ ___] &]


Also note that if the list is really large, using Pick in combination with the listable form of StringFreeQ is an order of a magnitude faster:

Pick[list, StringFreeQ[list, ___ ~~ "A" ~~ ___]]


The StringExpression doc says: Except[p]: any character except ones matching p. This seems to imply that Except[p] can only stand for a single character in this context and not a string.

• WRI is the master of implicit documentation... – Kuba May 21 '15 at 8:05
• @Christ, this hasn't been fixed since 2013? – alancalvitti May 13 at 22:16