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$
7
  • $\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
  • 1
    $\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$ 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$
    – Greg 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$ 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$
11
  • $\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
4
$\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$
1
  • $\begingroup$ See comments on Mr Wizard's answer regarding "*" acting as a wildcard $\endgroup$ Feb 3 '15 at 15:38
4
$\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$
2
  • $\begingroup$ This looks very interesting. My original problem came from analysing boxes so this sort of approach might fit nicely. $\endgroup$ 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.