balanced Shortest[] and string-patterns
This seems to work:
StringCases["blabla ...Hello Hello ... blabla ... Goobye Goobye ..",
Longest[___ ~~ a : "Hello"] ~~ b : Shortest[___ ~~ "Goobye"] :> a ~~ b]
Update
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}];
Flatten@f@str]
extractbetween["blah X first Y blah X second Y X third Y", "X", "Y"]
(* {"X first Y", "X second Y", "X third Y"} *)
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"} *)
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.