3
$\begingroup$

I have a string like this one

str = "this and that but also thit and that";

Now I want to extract, the first 3 letters before and after " and " so that the outcome is

{his and tha, hit and tha}

I tried it with

StringCases[str, 
 x__ ~~ " and " ~~ y__ :> {StringTake[x, -3], StringTake[y, 3]}]

but this extracts only the second substring {{"hit", "tha"}}. And using StringCases[str, _ ~~ " and " ~~ _] extracts only one letter {"s and t", "t and t"}. So is there a way to define a Blank with a particular length?

$\endgroup$
2

4 Answers 4

5
$\begingroup$
StringCases[str,   x__ ~~ " and " ~~ y__ /; StringLength[x] == StringLength[y] == 3]

or

StringCases[str, _ ~~ _ ~~ _ ~~ " and " ~~ _ ~~ _ ~~ _]

would work:

{"his and tha", "hit and tha"}
$\endgroup$
7
$\begingroup$

Using Repeated:

StringCases[
 str,
 Repeated[_, {3}] ~~ " and " ~~ Repeated[_, {3}],
 Overlaps -> True
 ]

{"his and tha", "hit and tha"}

Note the use of Overlaps which is necessary for strings such as

str = "this and that and thit and that";

With Overlaps -> True:

{"his and tha", "hat and thi", "hit and tha"}

with Overlaps -> False:

{"his and tha", "hit and tha"}

$\endgroup$
1
  • $\begingroup$ Your solution is neater and more detailed! $\endgroup$ Commented Jul 2, 2020 at 3:56
3
$\begingroup$

If the number of whitespaces before and after 'and' is unknown (but in each case there is at least one), a simple regex should do:

str = "this and that but also thit and that";
StringCases[str, RegularExpression[".{3}\s+and\s+.{3}"]]

{his and tha, hit and tha}

Alternatively, a positive lookahead may be used:

StringCases[str, RegularExpression["(?=(.{3}\s+and\s+.{3}))\\1"]]
StringCases[str, RegularExpression["(?=(.{3}\s+and\s+.{3}))"]:> "$1"]

{his and tha, hit and tha}

{his and tha, hit and tha}


For strings such as "this and that and thit and that" considered by C.E above:

str2 = "this and that and thit and that";
StringCases[str2, RegularExpression[".{3}\s+and\s+.{3}"], Overlaps:> True]
StringCases[str2, RegularExpression["(?=(.{3}\s+and\s+.{3}))\\1"],Overlaps->True]
StringCases[str2, RegularExpression["(?=(.{3}\s+and\s+.{3}))"]:> "$1"]

{his and tha, hat and thi, hit and tha}

{his and tha, hat and thi, hit and tha}

{his and tha, hat and thi, hit and tha}

In addition posix character classes are supported:

StringCases[str2, RegularExpression["[[:alnum:]]{3}[[:blank:]][Aa]nd[[:blank:]][[:alnum:]]{3}"], Overlaps:> True]

{his and tha, hat and thi, hit and tha}


For positive lookaheads, compare (see here):

s = "123456789123456789";
StringCases[s,RegularExpression["(?=(\d{10}))\\1"]]
StringCases[s,RegularExpression["(?=(\d{10}))\\1"],Overlaps:>True]
StringCases[s,RegularExpression["(?=(\d{10}))"]:> "$1"]

{1234567891}

{1234567891, 2345678912, 3456789123, 4567891234, 5678912345, 6789123456, 7891234567, 8912345678, 9123456789}

{1234567891, 2345678912, 3456789123, 4567891234, 5678912345, 6789123456, 7891234567, 8912345678, 9123456789}

$\endgroup$
0
2
$\begingroup$
foo[str_, n_] :=
 With[{s = StringSplit @ str},
  StringJoin @* Insert[" and ", 2] /@
   MapApply[StringTake[s[[#1]], #2] &] /@
    (Position[s, "and"] /. {x_} :> {{x - 1, -n}, {x + 1, n}})]

str = "this and that but also thit and that";

foo[str, #] & /@ {2, 3, 4}

{{"is and th", "it and th"},
{"his and tha", "hit and tha"},
{"this and that", "thit and that"}}

str = "this and that but also thit and that or even thot and thut";

foo[str, #] & /@ {2, 3, 4}

{{"is and th", "it and th", "ot and th"},
{"his and tha", "hit and tha", "hot and thu"},
{"this and that", "thit and that", "thot and thut"}}

$\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.