# How to extract a consecutive list of substring from a string?

Given a list of strings:

data = {
"2894;Hot Pink;53:09:44;1449714",
"17456;Dark Cyan;19:06:42;6929227",
"5147;Lime;54:11:55;5247632"
}


(Words are separated by ";", the number of words in strings are equal. Number of characters in strings are unequal. Number of characterss in words are unequal.)

How to extract the $m^{th}$ through $n^{th}$ words, so that e.g. $m=2, n=3$ should return:

{
"Hot Pink;53:09:44",
"Dark Cyan;19:06:42",
"Lime;54:11:55"
}


UPDATE

Final solution was found for the task.
I like to share it here.

inlist = RandomChoice[
{"7270;Deep Pink;04:14:55;0027354",
"2871;Dark Orchid;54:21:23;1182263",
"4021;Silver;04:00:58;6940040",
"3521;Dark Slate Gray;18:42:43;5828275"},
400000];

delim = ";";
fromWord = 2;
numberOfWords = 2;

from = 2 fromWord - 1;
to = 2 (fromWord + numberOfWords - 1) - 1;
outlist = List /@ StringJoin /@
StringSplit[inlist, delim -> delim][[All, from ;; to]]; // Timing

{0.92, Null}


The honor goes to the very concerned in this task. Every detail of their conception was vital to the solution. Keep'n rocking.

-

Specific case for $m=2$ and $n=3$:

data = {"2894;Hot Pink;53:09:44;1449714",
"17456;Dark Cyan;19:06:42;6929227",
"5147;Lime;54:11:55;5247632"};

First@StringCases[#,
StartOfString ~~ __ ~~ ";" ~~ x__ ~~ ";" ~~ y__ ~~ ";" :> x <> ";" <> y] & /@ data

{"Hot Pink;53:09:44", "Dark Cyan;19:06:42", "Lime;54:11:55"}


More general version for any $m, n$:

{m, n} = {2, 3}

StringDrop[StringJoin@Drop[
StringCases[#, Shortest[__ ~~ ";"], n], m - 1], -1] & /@ data

{"Hot Pink;53:09:44", "Dark Cyan;19:06:42", "Lime;54:11:55"}

-
Your result gives a 3 x 2 list. We need a list of 3 strings. Hot Pink;53:09:44 Dark Cyan;19:06:42 Lime;54:11:55 hp –  Hp Radojewski Schäfer Von Dec 21 '12 at 11:44
@HP Please see edit. Nasser: I hope you don't mind that I added the general case to your answer instead of creating a new one. It fits in nicely I think. I you feel otherwise, please don't hesitate to roll back. –  István Zachar Jan 5 '13 at 10:21
OK. . .Your function works well. . .It could not improve in timing compared to the algorithmic one shown below. –  Hp Radojewski Schäfer Von Jan 7 '13 at 7:56
Have an other look. It seems not to get the last words. . .If you do {m, n}={1, 4} –  Hp Radojewski Schäfer Von Jan 9 '13 at 17:01
f[data_, from_, to_, sep_] := StringSplit[#, sep][[from ;; to]] & /@ data;
data = {"2894;Hot Pink;53:09:44;1449714",
"17456;Dark Cyan;19:06:42;6929227",
"5147;Lime;54:11:55;5247632"};

f[data, 2, 3, ";"]
(*
->{{"Hot Pink", "53:09:44"}, {"Dark Cyan", "19:06:42"}, {"Lime", "54:11:55"}}
*)

-
@NasserM.Abbasi Of course I can't be sure, but my interpretation comes from the use of the word throughin the OP's sentence Give a list of strings containing chars m'th "Word" through n'th "Word" in elements –  belisarius Dec 20 '12 at 11:41
StringSplit is Listable. Try: f[data_, from_, to_, sep_] := StringSplit[data, sep][[All, from ;; to]] –  Mr.Wizard Dec 20 '12 at 11:55
Not quit what is expected. –  Hp Radojewski Schäfer Von Dec 21 '12 at 11:33
Will say, not a result with a 3 x 2 element list. It should be a list of 3 elements. The ";" sould be preserved. hp –  Hp Radojewski Schäfer Von Dec 21 '12 at 11:51
One could use Take[] instead of Part[]+Span[] of course... –  Guess who it is. Apr 4 '13 at 14:51

A solution was developed. Building a program working on two Streams. One record by one record.

instr = OpenRead[infile];
outstr = OpenAppend[outfile];
azr=3; (* number of records to work on *)
abw=2; (* first word in record to extract *)
azw=2; (* number of words to extract *)
delim=";" (* separator char *)

Do[rean = Read[instr, "Record", NullWords -> True];
arean = rean <> delim;
pos = Flatten[StringPosition[arean, delim]];
fla = Flatten[{0, Drop[pos, {1, Length[pos], 2}]}];
extract = StringTake[arean, {fla[[abw]] + 1, fla[[abw + azw]] - 1}];
WriteString[outstr, extract, "\n"],
{i, azr}]; // Timing


It is a kind of ugly. Could not find a function solution.

-