5
$\begingroup$

I would like to test strings to see if they represent numbers. This should include number representations with precision marks and scientific notation. NumberString is unfortunately more restrictive:

mylist = {"1.23", "1.23`", "1.23*^4", "Print[fail]"};

StringMatchQ[mylist, NumberString]
(* {True, False, False, False} *)

As a complication, I want to avoid converting the strings to expressions and testing with NumberQ, as some strings may contain code which is unsafe to evaluate.

How can I make a pattern like NumberString but which matches all of the first three elements in mylist?

$\endgroup$
  • $\begingroup$ Are you going to self-answer? I may dig into this if not. $\endgroup$ – Mr.Wizard Feb 3 '15 at 14:56
  • $\begingroup$ Also, is your reason for not converting to expressions only for safety as stated? $\endgroup$ – Mr.Wizard Feb 3 '15 at 14:57
  • $\begingroup$ @Mr.Wizard, no, I'm not planning to self answer. Yes, safety is basically the only reason - it would be okay to create a held expression for example. $\endgroup$ – Simon Woods Feb 3 '15 at 15:22
  • $\begingroup$ "I would like to test strings to see if they represent numbers." How strict are we talking here? Do you want the string "EulerGamma" to be considered a number, or are you referring to number in the sense of NumberQ? $\endgroup$ – Chip Hurst Feb 3 '15 at 19:30
  • 1
    $\begingroup$ @Mr.Wizard, the new pattern is definitely cleaner and it appears to work perfectly. Thank you. $\endgroup$ – Simon Woods Feb 12 '15 at 19:22
4
$\begingroup$

Edit: I came to realize that my original form was redundant. I now propose this instead:

p2 = 
  NumberString ~~ "" | "`" | ("`" | "``" ~~ NumberString) ~~ 
    "" | ("\\*^" | "\\*^-" ~~ DigitCharacter ..);

Test:

test = {"1.23`4.56*^-7", "1.23", "1.23`", "1.23``5", "1.23*^4", "Print[fail]"};

StringMatchQ[test, p2]
{True, True, True, True, True, False}
$\endgroup$
  • $\begingroup$ Actually you should write "\\*^", otherwise for example "1.23abc*^4" matches also True ! which is annoying for safety reasons !! $\endgroup$ – SquareOne Feb 3 '15 at 15:36
  • $\begingroup$ @SquareOne Right, sorry guys. $\endgroup$ – Mr.Wizard Feb 3 '15 at 15:36
  • 2
    $\begingroup$ I confirm you need 2 backslashes "\\*^" not "\*^" $\endgroup$ – SquareOne Feb 3 '15 at 15:39
  • $\begingroup$ @SquareOne Yuck! Of course. I really made a mess of this. Thanks. I'm not sure that is the only problem however. $\endgroup$ – Mr.Wizard Feb 3 '15 at 15:40
  • 1
    $\begingroup$ @Chip I think I addressed that. If you find any other problems please let me know. $\endgroup$ – Mr.Wizard Feb 9 '15 at 8:16
3
$\begingroup$

RegularExpression may be helpful, like this

In[109]:= 
mylist = {"1.23", "1.23`", "1.23*^4", "1.22*^-2", "Print[fail]"};
numberString = 
  RegularExpression[
    "[0-9]*.?[0-9]*`?"] | (RegularExpression["[0-9]*.?[0-9]*`?"] ~~ 
     "*^" ~~ RegularExpression["-?[0-9]+"]);
StringMatchQ[mylist, numberString]
Do[StringMatchQ[mylist, NumberString], {10^5}] // AbsoluteTiming
Do[StringMatchQ[mylist, numberString], {10^5}] // AbsoluteTiming

Out[111]= {True, True, True, True, False}

Out[112]= {0.607035, Null}

Out[113]= {0.917052, Null}
$\endgroup$
  • $\begingroup$ See comments on Mr Wizard's answer regarding "*" acting as a wildcard $\endgroup$ – Simon Woods Feb 3 '15 at 15:38
3
$\begingroup$

I'm not certain how general it is, but works :)

Just for fun, I've assumed that FrontEnd should know what is a number and what to split on boxes:

StringFreeQ[#, LetterCharacter] && c[#][[1, 1]] === # & /@ {

 "1.23", "1.23`", "1.23*^4", "Print[fail]", "string", "1`1", "1`1`1"}
{True, True, True, False, False, True, False}

Where c is UndocumentedTestFEParser generously introduced to us by John Fultz:

c = MathLink`CallFrontEnd[FrontEnd`UndocumentedTestFEParserPacket[#, True]] &
$\endgroup$
  • $\begingroup$ This looks very interesting. My original problem came from analysing boxes so this sort of approach might fit nicely. $\endgroup$ – Simon Woods Feb 3 '15 at 22:17
  • $\begingroup$ @SimonWoods :) great. Good luck then. $\endgroup$ – Kuba Feb 4 '15 at 7:33

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.