tl;dr: The behavior of AnyOrder
observed by the OP might be related to the way StringExpression
handles named patterns. A work around with SequencesCases
and OrderlessPatternSequence
can be used in principle for simple string patterns.
Analysis
It may be the case that AnyOrder
is translated into a form of Alternatives
and StringExpression
(not necessarily at top-level) where the names of the patterns are lost. This can be seen by noticing that the second output can be obtained with
(* Input 1 *)
StringCases["abc123 456def",
a : ( (l : LetterCharacter .. ~~ d : DigitCharacter ..) |
(DigitCharacter .. ~~ LetterCharacter ..)
) :> {a, {l, d}}
]
(* {{"abc123", {"abc", "123"}}, {"456def", {"", ""}}} *)
The alternative, where the pattern names are kept in the second argument of Alternatives
, makes StringExpression
throw warnings for the first evaluation and, more importantly, change the resulting expression:
(* Input 2 *)
StringCases["abc123 456def",
a : ( (l : LetterCharacter .. ~~ d : DigitCharacter ..) |
(d : DigitCharacter .. ~~ l : LetterCharacter ..)
) :> {a, {l, d}}
]
StringExpression::cond: Warning: restrictions on pattern variable d in d:(DigitCharacter..)
are ignored as they are not associated with the first occurrence of d.
StringExpression::cond: Warning: restrictions on pattern variable l in l:(LetterCharacter..)
are ignored as they are not associated with the first occurrence of l.
(* {{"abc123", {"abc", "123"}}} *)
So the issue may boil down to the way StringExpression
handles pattern, provided of course that the initial assumption about a translation was correct. This would explain why the pattern names are lost for another order of the given string patterns.
StringExpression warnings
The warnings seen above happen with simpler inputs where no Alternatives
is involved:
(* Input 3 *)
StringCases["aa", a : LetterCharacter ~~ a : LetterCharacter :> a]
StringExpression::cond: Warning: restrictions on pattern variable a in a:LetterCharacter
are ignored as they are not associated with the first occurrence of a.
(* {"a"} *)
The second pattern restriction, here LetterCharacter
, is ignored in the matching, which means that changing it to different pattern object, such as DigitCharacter
, will still work:
(* Input 4 *)
StringCases["aa", a : LetterCharacter ~~ a : DigitCharacter :> a]
StringExpression::cond: Warning: restrictions on pattern variable a in a:DigitCharacter
are ignored as they are not associated with the first occurrence of a.
(* {"a"} *)
We can therefore assume that Inputs 3
and 4
are viewed for the evaluation process as
StringCases["aa", a : LetterCharacter ~~ a_ :> a]
(* {"a"} *)
Applying this assumption to Input 2
, we can understand why we obtained the output {{"abc123", {"abc", "123"}}}
StringCases["abc123 456def",
a : ( (l : LetterCharacter .. ~~ d : DigitCharacter ..) |
(d_ ~~ l_)) :> {a, {l, d}}
]
(* {{"abc123", {"abc", "123"}}} *)
Further remarks and possible work around
It has to be noted that when using the following counterpart of Input 2
,
SequenceCases[Characters["abc123 456def"],
a : ( {l : _?LetterQ .., d : _?DigitQ ..} |
{d : _?DigitQ .., l : _?LetterQ ..}
) :> {StringJoin[a], {StringJoin[l], StringJoin[d]}}
]
(* {{"abc123", {"abc", "123"}}, {"456def", {"def", "456"}}} *)
we obtain the expected output. Re-expressing this input by means of OrderlessPatternSequence
, which brings the expression closer to OP's second input, also yields the same output
SequenceCases[Characters["abc123 456def"],
a : {OrderlessPatternSequence[l : _?LetterQ .., d : _?DigitQ ..]
} :> {StringJoin[a], {StringJoin[l], StringJoin[d]}}
]
(* {{"abc123", {"abc", "123"}}, {"456def", {"def", "456"}}} *)
This seems to imply that OrderlessPatternSequence
translates to Alternatives
(not necessarily at top-level), which makes the initial assumption about AnyOrder
plausible. So in the end, the behavior you mentioned might indeed be related to the way StringExpression
handles patterns.
As a last remark, using OrderlessPatternSequence
in the way above could be a workaround. But this is unfortunately viable to some extent only, since translating other string pattern specifications, such as for instance PunctuationCharacter
, WordBoundary
and Whitespace
, even though perhaps feasible, complicates the picture.
StringCases["abc123 456def 789ghi", a : AnyOrder[d : DigitCharacter .., l : LetterCharacter ..] :> {a, {d, l}}]
. You will notice that it only replaces the named patterns inAnyOrder
when their order in the string matches the order of the patterns as listed inAnyOrder
. $\endgroup$