17
$\begingroup$

If I have some string data:

text = StringTake[ExampleData[{"Text", "DeclarationOfIndependence"}], 400]

"When in the Course of human events, it becomes necessary for one people to dissolve the political bands which have connected them with another, and to assume, among the Powers of the earth, the separate and equal station to which the Laws of Nature and of Nature's God entitle them, a decent respect to the opinions of mankind requires that they should declare the causes which impel them to the sepa"

This is what I use to find a specific pattern inside and grab a bit more data around it:

StringCases[text, (y__ /;StringLength[y] == 4) ~~ "entitle" ~~ x__ /;StringLength[x] == 5]
{"God entitle them"}

Are there any alternatives, desirably neater ones? Maybe something with regular expressions?

$\endgroup$
3
  • 2
    $\begingroup$ So StringTake[text, First[StringPosition[text, "entitle"]] + {-4, 5}] isn't neat? $\endgroup$ Commented Aug 9, 2012 at 8:54
  • $\begingroup$ @J.M. It is, you should post it as an answer - I am looking for tidbits like this ;-) Hoping to get something with regular expressions too. $\endgroup$ Commented Aug 9, 2012 at 9:02
  • $\begingroup$ regexes in my answer $\endgroup$ Commented Aug 9, 2012 at 9:27

3 Answers 3

15
$\begingroup$

Per Vitaliy's request:

With[{before = 4, after = 5},
 StringTake[text, First[StringPosition[text, "entitle"]] + {-before, after}]]

yields "God entitle them".

$\endgroup$
13
$\begingroup$
StringCases[text, x___ ~~ "entitle" ~~ y___ :> 
   StringTake[x, -4] ~~ "entitle" ~~ StringTake[y, 5]]

or

StringCases[text, Repeated[_, 4] ~~ "entitle" ~~ Repeated[_, 5]]

Generalizing:

paddedString1[text_, string_, left_, right_] := 
 StringCases[text,  x___ ~~ string ~~ y___ :> 
  StringTake[x, -left] ~~ string ~~ StringTake[y, right]]

and

paddedString2[text_, string_, left_, right_] := 
 StringCases[text, Repeated[_, {left}] ~~ string ~~ Repeated[_, {right}]]
$\endgroup$
7
  • $\begingroup$ Interesting twist, thanks ;-) $\endgroup$ Commented Aug 9, 2012 at 10:01
  • 1
    $\begingroup$ I think the last one should be Repeated[_, {left}] ~~ string ~~ Repeated[_, {right}]? Repeated[_, n] means "repeated up to n times"; Repeated[_, {n}] is exactly n. $\endgroup$ Commented Aug 10, 2012 at 17:32
  • $\begingroup$ @OleksandrR., you are right ... Thank you. I thought --wrongly -- that n versus {n} would not make a difference for the pattern _ and chose to save some keystrokes. $\endgroup$
    – kglr
    Commented Aug 11, 2012 at 0:20
  • $\begingroup$ @Oleksandr when would the original produce an incorrect result? I find the behavior of the original highly desirable in that it gracefully handles sub-strings at the beginning and end of the text. If this were my question I would Accept this answer (in its original form) for that reason. $\endgroup$
    – Mr.Wizard
    Commented Aug 11, 2012 at 7:09
  • 1
    $\begingroup$ kguler, by the way, I happened to check your profile and you've been here every single day since the beginning. I don't know whether I should congratulate you or arrange an intervention. $\endgroup$
    – Mr.Wizard
    Commented Aug 11, 2012 at 7:22
12
$\begingroup$

Using regular expressions

f[text_, string_, before_, after_] := 
 StringCases[text, RegularExpression[".{" <> ToString@before <> "}" <> 
                                     string <> ".{" <> ToString@after <> "}"]]

f[text, "entitle", 4, 5]

(*{"God entitle them"}*)

(added by J. M.)

A more compact implementation of the function f[] is as follows:

f[text_String, string_String, before_Integer, after_Integer] :=
  StringCases[text, RegularExpression[ToString[StringForm[
              ".{`1`}" <> string <> ".{`2`}", before, after]]]]

The ToString[] is needed here since StringForm[], contrary to how it is named, does not return a String[] object, and thus a conversion has to be done.

$\endgroup$
6
  • 1
    $\begingroup$ Great thanks ;-) So ".{4}entitle.{5}" - is such notation mentioned in docs? It seems I've missed it. $\endgroup$ Commented Aug 9, 2012 at 9:38
  • 2
    $\begingroup$ @VitaliyKaurov The Regexp docs in the Mma help system are good, but not enough to learn regexes from zero. $\endgroup$ Commented Aug 9, 2012 at 9:49
  • 3
    $\begingroup$ @VitaliyKaurov The documentation mentions that Mathematica's regular expressions are implemented using PCRE. The PCRE and Perl regex man pages accurately document Mathematica's regex features. $\endgroup$
    – WReach
    Commented Aug 9, 2012 at 12:18
  • 1
    $\begingroup$ Here's an alternative implementation: f[text_, string_, before_, after_] := StringCases[text, RegularExpression[ToString[StringForm[".{`1`}" <> string <> ".{`2`}", before, after]]]] $\endgroup$ Commented Aug 12, 2012 at 4:59
  • $\begingroup$ @J.M. StringForm is one of those zillions of little Mma functions that make life easier, but I keep forgetting. As it is a real improvement (at least in readability), please consider to post an answer or edit mine. $\endgroup$ Commented Aug 12, 2012 at 5:04

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.