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, 2015 at 14:56
  • $\begingroup$ Also, is your reason for not converting to expressions only for safety as stated? $\endgroup$
    – Mr.Wizard
    Feb 3, 2015 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, 2015 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, 2015 at 19:30
  • 1
    $\begingroup$ @Mr.Wizard, the new pattern is definitely cleaner and it appears to work perfectly. Thank you. $\endgroup$ Feb 12, 2015 at 19:22

3 Answers 3

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, 2015 at 15:36
  • $\begingroup$ @SquareOne Right, sorry guys. $\endgroup$
    – Mr.Wizard
    Feb 3, 2015 at 15:36
  • 2
    $\begingroup$ I confirm you need 2 backslashes "\\*^" not "\*^" $\endgroup$
    – SquareOne
    Feb 3, 2015 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, 2015 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, 2015 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, 2015 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, 2015 at 22:17
  • $\begingroup$ @SimonWoods :) great. Good luck then. $\endgroup$
    – Kuba
    Feb 4, 2015 at 7:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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