4
$\begingroup$

I have a large string like this:

string = {"text, 1998, TEXTDATA, text, 2007, NEXTTEXTDATA"};

Now I want to extract TEXTDATA and NEXTTEXTDATA. I tried to use StringCases and Shortestin combination with DigitCharacterlike this:

StringCases[string, Shortest[DigitCharacter .. ~~ ___ ~~ ", "]]

but this of course yields only

(* {{"1998, ", "2007, "}} *)

So either there is a way to combine DigitCharacterwith the FIRST comma (and then probably Shortestwould work) or there is a way without Shortest?

$\endgroup$
4
  • $\begingroup$ do you mean you want to extract the uppercase text? $\endgroup$
    – Fraccalo
    Feb 18 '20 at 9:32
  • $\begingroup$ Or do you want to take the text appearing after a sequence of number and comma? $\endgroup$
    – Fraccalo
    Feb 18 '20 at 9:38
  • $\begingroup$ @Fraccalo yes but in this example, it is just uppercase for illustrative purposes... $\endgroup$
    – M.A.
    Feb 18 '20 at 9:38
  • $\begingroup$ @Fraccalo the text appearing between number+ FIRST comma and SECOND comma $\endgroup$
    – M.A.
    Feb 18 '20 at 9:40
4
$\begingroup$
StringCases[string, DigitCharacter .. ~~ ", " ~~ w : (LetterCharacter ..) :> w]

{{"TEXTDATA", "NEXTTEXTDATA"}}

or

StringCases[string, NumberString ~~ ", " ~~ w : (LetterCharacter ..) :> w]

{{"TEXTDATA", "NEXTTEXTDATA"}}

or

StringCases[string, ", " ~~ w : (LetterCharacter ..) ~~ EndOfString | "," :> w]

{{"TEXTDATA", "NEXTTEXTDATA"}}

$\endgroup$
5
  • $\begingroup$ string has a very simple structure. What if string contains other numbers and blanks? Is there a way to implement an exact rule: just (and only just) take the text between the 4-digit (its always a year but a string) and the SECOND comma AFTER this year-digit? $\endgroup$
    – M.A.
    Feb 18 '20 at 10:17
  • $\begingroup$ @M.A., you can try a more specific pattern like StringCases[string, Repeated[DigitCharacter, {4}] ~~ ", " ~~ w : (LetterCharacter ..) ~~ "," | EndOfString :> w] $\endgroup$
    – kglr
    Feb 18 '20 at 10:40
  • $\begingroup$ This appears to work only with "TEXTDATA" (again, sorry for my oversimplified string example). What if I have "A TEXT LIKE THIS" (with blanks)? $\endgroup$
    – M.A.
    Feb 18 '20 at 11:48
  • 1
    $\begingroup$ StringCases[string, Repeated[DigitCharacter, {4}] ~~ ", " ~~ w : (Except[","] ..) ~~ "," | EndOfString :> w]? $\endgroup$
    – kglr
    Feb 18 '20 at 12:02
  • $\begingroup$ Just a minor modification: StringCases[string, ", " ~~ Repeated[DigitCharacter, {4}] ~~ ", " ~~ w : (Except[","] ..) ~~ ", " | EndOfString :> w] This ensures that Strings like "P1675" are kicked out. Thx! $\endgroup$
    – M.A.
    Feb 18 '20 at 12:16
3
$\begingroup$

For the moment, it seems to suffice just to understand the selection criterion as to find all the substrings consisting of upper letters. To convey that information, one can use RegularExpression or CharacterRange to construct the string pattern.

string = {"text, 1998, TEXTDATA, text, 2007, NEXTTEXTDATA"};
stringpattern1 = RegularExpression["[[:upper:]]+"];
stringpattern2 = CharacterRange["A", "Z"] ..;
StringCases[string, stringpattern1]
StringCases[string, stringpattern2]

both with the same result

{{"TEXTDATA", "NEXTTEXTDATA"}}


If one has to work by specifying the environment of the substrings rather than the information of the target substrings themselves, the string pattern is also accessible as

stringpattern3 = RegularExpression["\\d, ([^ ,]+),?"] -> "$1";

which is saying "picking out whatever parenthesized characters except a blank or a comma, following a substring consisting of a digit, a comma, and a blank, and simultaneously followed by a comma or nothing (no more than one comma)".

$\endgroup$
2
  • $\begingroup$ (+1) I like stringpattern3 $\endgroup$
    – user1066
    Feb 18 '20 at 12:16
  • $\begingroup$ @user1066 Thanks! $\endgroup$ Feb 18 '20 at 12:30
2
$\begingroup$
string = {"text, 1998, TEXTDATA, text, 2007, NEXTTEXTDATA"};
list = StringSplit[string[[1]], ", "];
filter = RotateRight[StringMatchQ[list, NumberString]];

Pick[list, filter]

{"TEXTDATA", "NEXTTEXTDATA"}

$\endgroup$
1
$\begingroup$
StringCases[string, 
RegularExpression["[0-9]{4},\\s([A-Z]+)"]:> "$1"]

{{TEXTDATA, NEXTTEXTDATA}}

(In Mathematica, $1 refers to the capturing group (within the parentheses)).

string2 = {"text, 1993,         TEXTDATA, text, 2007, NEXTTEXTDATA"};

StringCases[string2, 
RegularExpression["[0-9]{4},\\s+([A-Z]+)"]:> "$1"]

{{TEXTDATA, NEXTTEXTDATA}}

Edit

For " just (and only just) take the text between the 4-digit (its always a year but a string) and the SECOND comma AFTER this year-digit", maybe:

StringCases[string, 
RegularExpression[",\\s+[0-9]{4},\\s+([A-Z]+)"]:> "$1"]

{{TEXTDATA, NEXTTEXTDATA}}

Edit 2

Answering a comment by the OP:

" What if [...] "TEXT DATA" or "NEXT TEXT DATA"?

Such a case is easily handled by a RegExp by modification of the capturing group:

string3 = {"text, 1993,         TEXT DATA, text, 2007, NEXT TEXT DATA"};

StringCases[string3, 
RegularExpression["[0-9]{4},\\s+([A-Z\s]+)"]:> "$1"]

{{TEXT DATA, NEXT TEXT DATA}}

Edit 3

For a more complex string:

string4 = {"text, 1993,         TEXT-DATA, text, 2007, NEXT/TEXT (2004) DATA"};

The regex may be modified as follows (one way!):

StringCases[string4, 
RegularExpression["[0-9]{4},\\s+([A-Z0-9\s-()/]+)"]:> "$1"]

{{TEXT-DATA, NEXT/TEXT (2004) DATA}}

$\endgroup$
6
  • $\begingroup$ See also my comment to the answer of @kglr: What if I have "TEXT DATA" or "NEXT TEXT DATA"? $\endgroup$
    – M.A.
    Feb 18 '20 at 11:49
  • 2
    $\begingroup$ @M.A. Such a case is easily handled by regexp. See edit $\endgroup$
    – user1066
    Feb 18 '20 at 12:00
  • $\begingroup$ very impressive but (for me!) the solution from kglr is more understandable... $\endgroup$
    – M.A.
    Feb 18 '20 at 12:25
  • $\begingroup$ Maybe. But (borrowing heavily from @Αλέξανδρος Ζεγγ) StringCases[string, RegularExpression["[0-9]{4},\\s+([^,]+),?"]:> "$1"] is very understandable to me, and seems to tersely and specifically meet all your requirements. $\endgroup$
    – user1066
    Feb 18 '20 at 13:45
  • 1
    $\begingroup$ Substituting RegularExpression["[^A-Za-z][0-9]{4} ..." (four-digit number that cannot be preceded by any letter, uppercase or lowercase), RegularExpression["\\s[0-9]{4} ..." (four-digit number preceded by a single whitespace) or RegularExpression[",\\s+[0-9]{4} ..." (comma, followed an one-or-more whitespace(s), followed by four-digit number) are possible solutions to that scenario (see my answer). $\endgroup$
    – user1066
    Feb 18 '20 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.