Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

If I have a list of strings Like:

text = Select[
  StringSplit[
   StringReplace[
    StringTake[ExampleData[{"Text", "AliceInWonderland"}], {25, 997}], 
    Alternatives @@ Characters["<>?;'|:\"()-_!&"] -> " "], "." | ","],
   StringLength[#] > 2 &]

{"Alice was beginning to get very tired of sitting by her sister on the bank"," and of having nothing to do"," Once or twice she had peeped into the book her sister was reading"," but it had no pictures or conversations in it"," and what is the use of a book"," thought Alice"," without pictures or conversations So she was considering in her own mind as well as she could"," for the day made her feel very sleepy and stupid "," whether the pleasure of making a daisy chain would be worth the trouble of getting up and picking the daisies"," when suddenly a White Rabbit with pink eyes ran close by her"," There was nothing so very remarkable in that"," nor did Alice think it so very much out of the way to hear the Rabbit say to itself"," Oh dear Oh dear I shall be too late But when the Rabbit actually took a watch out of its waistcoat pocket and looked at it and then hurried on"," Alice started to her feet"," for it flashed across her mind that she had never before seen a rabbit with "}

how do I find the positions of the list elements that contain the following words/character strings:

words = {"her", "she", "alice", "bbit"};

Following on from this question, I tried using Position like so:

Position[text, 
 s_ /; StringMatchQ[s, __ ~~ Alternatives @@ words ~~ __, 
    IgnoreCase -> True] &]

{}

but this doesn't produce the list of positions. The follwing seems to suggest that I have the right string-matching criteria:

StringMatchQ[text, __ ~~ Alternatives @@ words ~~ __, 
 IgnoreCase -> True]

{True,False,True,False,False,False,True,True,True,True,True,True,True,True,True}

What am I missing?

share|improve this question

2 Answers 2

up vote 6 down vote accepted

StringPosition[] supports the useful form:

StringPosition[ {string1, string2 ...}, {patt1, patt2, ...} ]

So:

Position[StringPosition[text, words, IgnoreCase -> True], Except@{}, 1, Heads -> False]

{{1}, {3}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}}

Edit

This approach seems much faster than using conditional pattern matching:

text = Join @@ Array[Select[StringSplit[StringReplace[StringTake[
               ExampleData[{"Text", "AliceInWonderland"}], {25, 997}], 
              Alternatives @@ Characters["<>?;'|:\"()-_!&"] -> " "], 
              "." | ","], StringLength[#] > 2 &] &, 1000];
words = {"her", "she", "alice", "bbit"}; 

First@Timing@Position[
    text,
    s_ /; StringMatchQ[s, ___ ~~ Alternatives @@ words ~~ ___, IgnoreCase -> True],
    Heads -> False]

First@Timing@Position[
    StringPosition[text, words, IgnoreCase -> True],
    Except@{},
    1, Heads -> False]

First@Timing@Position[
    StringMatchQ[text, ___ ~~ Alternatives @@ words ~~ ___, IgnoreCase -> True],
    True]

0.168
0.042
0.044

share|improve this answer
1  
Using the listability of StringMatchQ it gets comparable speeds: Position[StringMatchQ[text, ___ ~~ Alternatives @@ words ~~ ___, IgnoreCase -> True], True] or Pick[Range[Length[text]], StringMatchQ[text, ___ ~~ Alternatives @@ words ~~ ___, IgnoreCase -> True]] –  ssch Sep 22 '13 at 20:07
    
@ssch Could you edit my answer comparing the three methods? –  belisarius Sep 22 '13 at 20:35

I misunderstood the question first...

I think you want to get rid of the & in Position:

Position[text, 
         s_ /; StringMatchQ[s, ___ ~~ Alternatives @@ words ~~ ___, 
         IgnoreCase -> True], Heads -> False]

(* {{1}, {3}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}} *)

As it is pattern /; expression and not pattern/;function

Edit old answer

You can use StringPosition:

matches = StringPosition[text, Alternatives @@ words]
(* {{{53, 55}}, {}, {{16, 18}, {45, 47}}, {}, {}, {}, {{42, 44}, {65, 
   67}, {90, 92}}, {{19, 21}}, {{6, 8}}, {{26, 29}, {59, 61}}, {{3, 
   5}}, {{67, 70}}, {{58, 61}}, {{19, 21}}, {{12, 14}, {24, 26}, {38, 
   40}, {68, 71}}} *)

MapThread[
 StringReplacePart[#1, ToUpperCase[StringTake[#1, #2]], #2] &,
 {text, matches}]
(* {
  "Alice was beginning to get very tired of sitting by HER sister on the bank",
  " and of having nothing to do",
  " Once or twice SHE had peeped into the book HER sister was reading",
  " but it had no pictures or conversations in it",
  "  and what is the use of a book", 
  "  thought Alice", 
  "  without pictures or conversations   So SHE was considering in HER own mind  as well as SHE could",
  " for the day made HER feel very sleepy and stupid ",
  " whetHER the pleasure of making a daisy chain would be worth the trouble of getting up and picking the daisies",
  " when suddenly a White RaBBIT with pink eyes ran close by HER",
  " THERe was nothing so very remarkable in that",
  " nor did Alice think it so very much out of the way to hear the RaBBIT say to itself",
  "  Oh dear  Oh dear  I shall be too late   But when the RaBBIT actually took a watch out of its waistcoat pocket and looked at it and then hurried on",
  " Alice started to HER feet", " for it flaSHEd across HER mind that SHE had never before seen a raBBIT with "} *)
share|improve this answer
    
You suggestion tells me where these words occur within each list element, but not which elements contain any of these words. Also, "alice" wasn't found (simply add IgnoreCase->True). –  geordie Sep 22 '13 at 14:44
    
@geordie how about now? :) –  ssch Sep 22 '13 at 14:46
    
Yep, that works nicely. Thanks! btw. Why is it necessary to set Heads -> False? Is this the same as adding 'levelspec' to Position(e.g. Position[list, blah, {1}])? –  geordie Sep 22 '13 at 14:55
1  
It's so it doesn't try to StringMatchQ[List,...] changing the pattern to s_String would have the same effect. It is distinct from levelspec. –  ssch Sep 22 '13 at 14:58
1  
@belisarius thanks! –  ssch Sep 22 '13 at 15:11

Your Answer

 
discard

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.