4
$\begingroup$

I want to partition string into longest substrings that each contain only specific characters, beginning from left to right with no overlaps, always choosing the longest one possible at current position. In my example only substrings that contain only characters d,f,g or d,e,h or a,b,c,g are allowed.

Example:

input:

StringCases["ABCDEFGH",Longest[("D"|"F"|"G")..|("D"|"E"|"H")..|("A"|"B"|"C"|"G")..]]

output:

{"ABC","D","E","FG","H"}

But after "ABC" there is evidently substring "DE" that is longer than "D" or "E". So my expected output would be:{ABC,DE,FG,H}

If I switch first and second argument of Alternatives this way:

StringCases["ABCDEFGH",Longest[("D"|"E"|"H")..|("D"|"F"|"G")..|("A"|"B"|"C"|"G")..]]

then output is as expected:

{"ABC","DE","FG","H"}

But Alternatives should be from definition something that is independent on arguments order. So I would expect in both inputs the same output (second one).

So my question is how to do it that I get always longest possible substring no matter what order of arguments inside Alternatives is?

$\endgroup$

2 Answers 2

6
$\begingroup$

You could do:

StringCases[
    "ABCDEFGH",
    Longest[p__] /; StringMatchQ[p,("D"|"F"|"G")..|("D"|"E"|"H")..|("A"|"B"|"C"|"G")..]
]

{"ABC", "DE", "FG", "H"}

$\endgroup$
1
  • $\begingroup$ Yes, works as I wanted. But I hoped for a more efficient method. I can do it much faster using two nested While loops, taking character by character till all of them belong to one set of characters. Anyway, I accept your answer. $\endgroup$ Commented Feb 28, 2019 at 11:10
3
$\begingroup$

But Alternatives should be from definition something that is independent on arguments order.

StringCases is based on the PCRE regular expression engine for which it isn't true: a regex engine always returns the first match from listed in alternation (when it allows to match the whole pattern).

To get the behavior you expected you should use SequenceCases instead (which doesn't use regexes and is based on Mathematica's own pattern-matcher):

StringJoin @@@ 
 SequenceCases[
  Characters@"ABCDEFGH", 
      {Longest[("D" | "F" | "G") .. | ("D" | "E" | "H") .. | 
               ("A" | "B" | "C" | "G") ..]}]
{"ABC", "DE", "FG", "H"}
$\endgroup$

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.