10
$\begingroup$

The following works as expected.

StringReplace["xxxyxz", "x" ~~ _ -> "ww"]

"wwwwww"

And so does this.

StringReplace["xxxyxz", {"xy" -> "xy", "x" ~~ _ -> "ww"}]
"wwxyww"

I expected the following to return "wwxyww" as well, but it emits an error message and returns unevaluated.

StringReplace["xxxyxz", Except["xy", "x" ~~ _] -> "ww"]

StringExpression::invld: Element Except[xy, x ~~ _] is not a valid string or pattern element in Except[xy, x ~~ _]. >>

StringReplace["xxxyxz", Except["xy", "x" ~~ _] -> "ww"]

I got this result in both V9 and V10. It looks like a bug to me, but before I report it as such, I thought I would ask the community whether or not this is actually valid behavior and, if it is valid, why?

$\endgroup$
  • $\begingroup$ @SjoerdC.deVries. Your 1st comment would certainly explain my result. Checking the documentation once more, all the examples I can find of Except used in string operations support your assertion. Can you point me to anywhere it is explicitly documented? Your 2nd comment can be applied not only to this toy problem, but to my real problem as well. If you write it up I will up-vote it and accept it. $\endgroup$ – m_goldberg Dec 6 '14 at 22:03
  • 3
    $\begingroup$ The Details section of StringExpression explicitly, if cryptically, states that Except can be used to match either a single character or a string position. It also implicitly suggests that the only valid arguments are those patterns listed within the sections detailing classes of characters or positions in strings. Experimentation supports this interpretation. All of this requires a pretty close reading -- I would prefer more direct statements of these points within the documentation. $\endgroup$ – WReach Dec 7 '14 at 1:33
10
$\begingroup$

It is my impression (based solely on the examples in the documentation) that in the context of strings Except only allows single-letter strings. Compare

StringMatchQ["q", Except["p"]] 

True

with

StringMatchQ["qq", Except["pp"]]

Mathematica graphics

Therefore, you generally need to rephrase your string patterns using the StringPattern and RegularExpression syntax. The one in your question could be rewritten as

StringReplace["xxxyxz", "x" ~~ Except["y"] -> "ww"]

"wwxyww"

One problem of constructions of this type: The simple Except["abcd"] with the intended meaning every string that is not identical to "abcd" is rather clumsy to rewrite in this way. It would be something like:

Repeated[_,3]|Except["a"]~~_~~_~~_|_~~Except["b"]~~_~~_|_~~_~~Except["c"]~~_|
_~~_~~_~~Except["d"]|Repeated[_, {5, Infinity}]

Not very elegant. It's probably better to use:

StringMatchQ["abcd", p : ___ /; p =!= "abcd"]

False

or in your case:

StringReplace["xxxyxz", p : ("x" ~~ _) /; p =!= "xy" -> "ww"]

"wwxyww"

$\endgroup$
4
$\begingroup$

The other commentators are correct that Except does only allow single-letter strings.

Note that you could also use RegularExpression here:

StringReplace["xxxyxz", RegularExpression["x[^y]"] -> "ww"]
$\endgroup$

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.