Okay, I think here's a way you can do virtually everything you want.
First, my original answer, which I then had then moved to a comment to Mr.Wizard's answer.
You can substitute in Unique
:
StringMatchQ[#, StringExpression @@ With[{each = p__ /; endsWithSpaceQ@p}, Table[each /. p -> Unique[], {2}]] ~~ "17"] & /@ {str1, str2}
(* {True, True} *)
This gives you what you want for your specific case.
But, you may want to have an arbitrarily long repeated sequence. Meaning, you don't know if it will repeat exactly 2 times or 3 times. The above doesn't do that.
Well, now, I don't know how to do it completely arbitrarily, but if you're willing to choose some maximum, then the following seems to work (but please correct me if I'm wrong):
StringMatchQ[#, Table[StringExpression @@ With[With[{each = p__ /; endsWithSpaceQ[p]}, Table[eachStringMatchQ[#, Table[StringExpression @@ Table[each /. p -> Unique[], {i}]]], {i, 10 10}] ~~ "17"] "17"] & /@ {str1, str2}]
(replace the "10" in the last iterator with whatever your maximum is)
The way it works is to first create the sequence of patterns programmatically, as Mr.Wizard suggested. For that, it replicates the "p" pattern a certain i
number of times and replaces it with a unique symbol each time it appears. Then, the outer table iterates i
up through the maximum. A list of StringExpression
's evaluates as an alternative, so as long as one of those patterns matches, it goes on.
Here's a way to see that it is really working. Let's change your function a little bit:
endsWithSpaceQn[str_, lenprespace_: 3] := StringEndsQ[str, " "] && StringLength@str == lenprespace + 1
now we are looking for strings that end with a space and are of length 3 (not counting the space)
Running the abovethis:
With[{each = p__ /; endsWithSpaceQn[p, 3]}, StringMatchQ[#, Table[StringExpression @@ Table[each /. p -> Unique[], {i}], {i, 10}] ~~ "17"] & /@ {str1, str2}]
with any maximum greater than 1 in the final iterator (where the 10
is), results in the correct answer:
(* {True, True} *)
But if you replace the 10
with a 1
then you'll see it comes back as:
(* {False, False} *)
(if you had used the original endsWithSpaceQ
function here, it would still come back true, because it would match eg "abc abc ")