Mathematica Stack Exchange is a question and answer site for users of Mathematica. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

The pattern Shortest["A"~~__~~"B"] is oriented : It assumes the text is read from left to right and it takes the text between the first "A" and the next "B". Any "A" after the first "A" is considered as normal text.

I want to select a text between the last "A" and the first "B".

This problem can be solved with Except["A"], but I don't find a clean solution when "A" is a string with more than one character.

Example :

    "blabla ...Hello Hello ... blabla ... Goodbye Goodbye ..",  
     Shortest["Hello" ~~ ___ ~~ "Goodbye"]

gives : {"Hello Hello ... blabla ... Goodbye"}

I would like : {"Hello ... blabla ... Goodbye"}.


If there are several sequences Hello ...Goodbye (not nested), It should make a List of them.

share|improve this question
up vote 7 down vote accepted
 shortestStringCases[str_String, from_String, to_String] := 
   StringCases[ str, (from ~~ mid___ ~~ to) /; StringFreeQ[mid, {from, to}]]
 shortestStringCases["blah X blah X first Y blah X blah X second Y", "X", "Y"]
 (* {"X first Y", "X second Y"} *)
share|improve this answer
What I like in the solution shortestStringCases[] is the clarity of the code. One see immediately what it does and that it is balanced. May be not efficient but good as specification. – andre Jan 22 '13 at 22:16

This seems to work:

StringCases["blabla ...Hello Hello ... blabla ... Goobye Goobye ..", 
 Longest[___ ~~ a : "Hello"] ~~ b : Shortest[___ ~~ "Goobye"] :> a ~~ b]


If there are multiple substrings to extract you can use recursion:

extractbetween[str_, x_, y_] := Module[{f},
  f[s_] := StringCases[s, 
   Longest[a___ ~~ x] ~~ b : Shortest[___ ~~ y] :> {f[a], x ~~ b}];

extractbetween["blah X first Y blah X second Y X third Y", "X", "Y"]
(* {"X first Y", "X second Y", "X third Y"} *)
share|improve this answer
Interesting, but I have forgotten to mention that there are several sequences Hello Hello... Goodbye in the same text. That's a problem with your suggestion. – andre Jan 21 '13 at 23:16

A possible solution is just to replace your boundary words with single characters. I think what you are venturing into is something akin to look-behind, which I don't think is supported. Anyways here's how I would do it:

boundary = {"Hello", "Goobye"};
limits = {"\[FormalCapitalX]", "\[FormalCapitalY]"};

shift[str_, from_, to_] := StringReplace[str, Rule @@@ Transpose[{from, to}]]

Just to have more then one match, I changed the test string

test = "blabla ...Hello Hello ... blabla ... Goobye
            Goobye .... Hello ... blabla2... Goobye";

shift[#, limits, boundary] & /@ 
  StringCases[shift[test, boundary, limits], 
  Shortest[limits[[1]] ~~ (Except[limits[[1]]] ...) ~~ limits[[2]]]]
(* {"Hello ... blabla ... Goobye"  , "Hello ... blabla2... Goobye"}  *)

Depending on your input, the substitution characters might need to be more carefully selected.

share|improve this answer
Until yet I use only ASCII character (in this problem). I must see how string-patterns interacts with special characters. Further information in half a day. – andre Jan 22 '13 at 8:07
I think the trick is that Except doesn't accept a String apart from when the String represents a special character. Strange. May be there's a more general way to force Except to take a String ? – andre Jan 22 '13 at 19:07
@andre I would expect it's a case of how the regular expression is implimented. To get some feeling for it here's a video of converting regular expressions into finite state automaton. The thing is that deteting when you reach a single token is different from keeping a seperate memory of which tokens you have been through and detecting whether they make up a specific series. – jVincent Jan 22 '13 at 23:00
Regular expressions can manage Except["Hello"]. Except["AB"] is : "(?ms)(?:[^A]|A[^B])" (try StringPattern``PatternConvert[(Except["A"] | ("A" ~~ Except["B"]) )]) Here is a myExcept[] which generalize Except : myExcept[str_String]:=str // NestList[StringDrop[#,{-1}]&,#,StringLength[#]-1]& // Reverse // (StringJoin[StringDrop[#,{-1}],"[^",StringTake[#,{-1}],"]"]& /@ # &) // Riffle[#,"|"]& // StringJoin["(?ms)(?:",#,")"]& // RegularExpression; don't know if it works with special characters – andre Jan 26 '13 at 12:28
(3 years later) The right solution with a regular expression has just been added by Alexey Popkov. See below his answer to my question. – andre Apr 4 at 15:25

One can use here regular expression with Negative Lookahead (?!regex) Before the Match in the same way as shown in this answer:

StringCases["blabla ...Hello Hello ... blabla ... Goodbye Goodbye ..", 
 "Hello" ~~ RegularExpression["(?:(?!Hello).)*?"] ~~ "Goodbye"]
{"Hello ... blabla ... Goodbye"}
StringCases["blabla ...Hello Hello ... blabla ... Goodbye Goodbye ..", 
{"Hello ... blabla ... Goodbye"}

A detailed description of this method can be found here.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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