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.

Say I have a string that contains numbers and words, such as this one:

string = "there are 1234 words and numbers 5678 in here $999";

How would I separate the string into an ordered list containing sublists populated with words and numbers? The ideal list would look like this:

idealList = {{there are}, {1234}, {words and numbers}, {5678}, {in here}, {$999}}

I know how to extract all words and all numbers, but I can't create a list like the previous one.


Here's an example of what I tried to extract words and its output:

StringCases[string, RegularExpression["\\w(?<!\\d)[\\w'-]*"]]
{there, are, words, and, numbers, in, here}

I can also do this with pattern-matching instead of RegEx, but it doesn't get me closer to my goal.

Is my regex simply wrong, or does this problem require a tiny bit more involved solution?

share|improve this question
    
In my view using regular expression is not good, in the sense that use of regular expression degrades the performance, it take more time. –  user1674 Jul 5 '12 at 4:14
    
@gaurab: in the absence of concrete evidence (e.g. timing results) to back up your claim, your words are far from being an answer. I have thus turned your "answer" into a comment. –  J. M. Jul 5 '12 at 4:23

4 Answers 4

up vote 12 down vote accepted

What about this?

StringSplit[string, i : NumberString :> i]

Ok, everyone's giving answers that actually work with the $, so here's an edit, as @kguler and @MrWizard suggested

StringSplit[string, i : ("" | "$" ~~ NumberString) :> i] // StringTrim
share|improve this answer
    
This works, but can you explain how it works please? –  CHM Jul 5 '12 at 0:51
    
@CHM, it splits the strings where it finds a NumberString, keeping the NumberString –  Rojo Jul 5 '12 at 0:52
    
You can also modify the pattern to use Alternatives as in StringSplit[string, i : NumberString | StringExpression["$" ~~ NumberString] :> i] or, StringSplit[string, i : NumberString | ("$" ~~ NumberString) :> i] (+1). –  kguler Jul 5 '12 at 4:22
    
+1 -- however, I think you shouldn't need StringTrim after using StringSplit[string]. –  Mr.Wizard Jul 5 '12 at 9:02
    
@kguler, I edited. I had first tried that but fast and was bitten by ~~ vs |'s precedence and didn't spend a second realising that was the issue –  Rojo Jul 5 '12 at 12:25

Note that Rojo's solution splits the expression containing the dollar sign as well:

StringSplit["there are 1234 words and numbers 5678 in here $999", i : NumberString :> i]
{"there are ", "1234", " words and numbers ", "5678", " in here $", "999"}

If you don't want that splitting to happen, here's one way, using a regex:

StringSplit["there are 1234 words and numbers 5678 in here $999",
            s : RegularExpression[".(\\d+)."] :> s]
{"there are", " 1234 ", "words and numbers", " 5678 ", "in here ", "$999"}

If the spaces in the ends of the strings are bothersome, you can use StringTrim[] to get rid of them:

StringSplit["there are 1234 words and numbers 5678 in here $999",
            s : RegularExpression[".(\\d+)."] :> s] // StringTrim
{"there are", "1234", "words and numbers", "5678", "in here", "$999"}

As another example:

str1 = "At 50x magnification, they'd better be paying me $1080 in 9 installments!";

StringSplit[str1, s : RegularExpression[".(\\d+)."] :> s] // StringTrim
{"At", "50x", "magnification, they'd better be paying me", "$1080", "in",
 "9", "installments!"}

The other methods presented would perform a splitting like

{"At", "50", "x magnification, they'd better be paying me", "$1080", "in",
 "9", "installments!"}

which may or may not be the desired behavior...

share|improve this answer
    
One could of course use a StringExpression[] instead of a RegularExpression[]: s : (_ ~~ DigitCharacter .. ~~ _) :> s. –  J. M. Jul 5 '12 at 4:06
    
StringSplit["there are 1234 words and numbers 5678 in here $999", RegularExpression["\\$?(\\d)+"] -> "$0"] // StringTrima little bit more compact –  Murta Jan 22 '13 at 0:22

Further variations:

using StringReplace:

List @@ StringTrim /@ StringReplace[string, 
    a : Except[{"$", DigitCharacter}] .. | NumberString | ("$" ~~ NumberString) :> {a}]

or, using the same replacement rule in StringCases:

 StringTrim /@ StringCases[string, 
   a : Except[{"$", DigitCharacter}] .. | NumberString | ("$" ~~ NumberString) :> {a}]

both yield:

enter image description here

share|improve this answer

I prefer the solutions given by Rojo and J.M. to the following one. But if you want to see a working version of your original approach with StringCases and RegularExpression, here is one possibility

StringCases[string, RegularExpression["([A-Za-z]|\\s)+|(\\$|\\d)+"]]

It returns

{"there are ", "1234", " words and numbers ", "5678", " in here ","$999"}

and as J.M. suggests above, apply StringTrim if desired. Handling decimals could also easily be added.

share|improve this answer
    
Instead of the pattern [A-Za-z] in the regex, you could use [[:alpha:]]. –  J. M. Jul 5 '12 at 3:57
    
Ah nice, I couldn't think of a more proper RegEx. Only ick is that there are spaces before and after " words and numbers ". –  CHM Jul 8 '12 at 16:32

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.