7
$\begingroup$

Alternatives seems to work fine with these simple patterns

StringMatchQ["Eric", Alternatives["Eric", "Geoff"]]    
(* True *)

StringMatchQ["Eric", Alternatives["Geoff", "Eric"]]
(* True *)

I have a more complex pattern that matches strings enclosed with parenthesis and optionally the string "sh" at the end. The patterns are below where I assign them to a variable

patternText = 
 StartOfString ~~ "(" ~~ 
  textContent : ((Join[{WordCharacter}, {"-", "+", "\\", ".", ",", 
        "/", ":", " "}] ..)) ~~ ")" ~~ EndOfString

patternTextShow = 
 StartOfString ~~ "(" ~~ 
  textContent : (Join[{WordCharacter}, {"-", "+", "\\", ".", ",", "/",
        ":", " "}] ..) ~~ ")sh" ~~ EndOfString

The patterns work fine by themselves

StringMatchQ["(Eric)", patternText]
(* True *)

StringMatchQ["(Eric)", patternTextShow]
    (* False *)

StringMatchQ["(Eric)sh", patternText]
(* False *)

StringMatchQ["(Eric)sh", patternTextShow]
(* True *)

The results are as expected.

When I use Alternatives, however, it only works if the matching pattern is first, fails otherwise.

StringMatchQ["(Eric)", Alternatives[patternTextShow, patternText]]
(* False *)

StringMatchQ["(Eric)", Alternatives[patternText, patternTextShow]]
(* True *)

StringMatchQ["(Eric)sh", Alternatives[patternTextShow, patternText]]
(* True *)

StringMatchQ["(Eric)sh", Alternatives[patternText, patternTextShow]]
(* False *)

Why is this?

I found that using Or solved the problem but would like to understand why the Alternatives approach fails.

Or[
 StringMatchQ["(Eric)", patternTextShow],
 StringMatchQ["(Eric)", patternText]
 ]
(* True *)

Or[
 StringMatchQ["(Eric)", patternText],
 StringMatchQ["(Eric)", patternTextShow]
 ]
(* True *)

Or[
 StringMatchQ["(Eric)sh", patternTextShow],
 StringMatchQ["(Eric)sh", patternText]
 ]
(* True *)

Or[
 StringMatchQ["(Eric)sh", patternText],
 StringMatchQ["(Eric)sh", patternTextShow]
 ]

(* True *)
$\endgroup$
2
  • $\begingroup$ I would love to. There used to be an In Out merge in the Markup menu but I no longer see it. Can you refresh my memory as to how to do it? Meanwhile I will manually edit. $\endgroup$ Commented Nov 29, 2020 at 17:39
  • $\begingroup$ Unfortunately I don’t know of an automated way here in the editor. Normally when I copy code from MMA by selecting it and CTRL+C, the In and Out don’t come with it. In fact I was wondering how you had gotten them in the first place :-) Thank you for editing them out. $\endgroup$
    – MarcoB
    Commented Nov 29, 2020 at 17:53

1 Answer 1

8
$\begingroup$

The problem arises from naming the inner sub-patterns in your two pattern definitions with the same identifier. When you combine the patterns with Alternatives, you then have a pattern with two sub-patterns tagged with the same name, which is bad.

Consider this simpler case.

pattern1 = StartOfString ~~ "(" ~~ t : WordCharacter .. ~~ ")1" ~~ EndOfString;
pattern2 = StartOfString ~~ "(" ~~ t : WordCharacter .. ~~ ")2" ~~ EndOfString;
StringMatchQ["(Eric)1", pattern1 | pattern2]
StringMatchQ["(Eric)1", pattern2 | pattern1]
StringMatchQ["(Eric)2", pattern1 | pattern2]
StringMatchQ["(Eric)2", pattern2 | pattern1]

True
False
False
True

It is corrected by giving the tagged sub-patterns different names.

pattern1 = StartOfString ~~ "(" ~~ s : WordCharacter .. ~~ ")1" ~~ EndOfString;
pattern2 = StartOfString ~~ "(" ~~ t : WordCharacter .. ~~ ")2" ~~ EndOfString;
StringMatchQ["(Eric)1", pattern1 | pattern2]
StringMatchQ["(Eric)1", pattern2 | pattern1]
StringMatchQ["(Eric)2", pattern1 | pattern2]
StringMatchQ["(Eric)2", pattern2 | pattern1]

True
True
True
True

$\endgroup$
1
  • $\begingroup$ You nailed it. Thank you. When I named the patterns and used the variable names it obscured the fact that the identifier names were identical. $\endgroup$ Commented Nov 29, 2020 at 18:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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