1

I thought (defun string-integer-p (string) was cool, I found it in the emacswiki.

Is there a variant of it I can use to test if string contains float eg. "8.3"

Drew
  • 77,472
  • 10
  • 114
  • 243
american-ninja-warrior
  • 3,903
  • 2
  • 24
  • 44
  • Emacs Wiki: (defun string-float-p (string) (if (string-match "\\[-+]?[0-9]+\.[0-9]*\'" string) t nil))` -- https://www.emacswiki.org/emacs/ElispCookbook – lawlist Jul 08 '18 at 22:40
  • 1
    Please provide the code for string-integer-p in the question, or at least link to the wiki page that defines it. – Drew Jul 09 '18 at 00:48
  • @lawlist: Please consider posting that as an answer. – Drew Jul 09 '18 at 00:48
  • @lawlist That solution neglects all the problems that result from exponent representation. – Tobias Jul 09 '18 at 15:15

3 Answers3

3

Since one can edit program texts in many programming languages with emacs it is important to note that the floating point syntax can vary with the programming language. For an instance 1.2d3 is a floating point number in Fortran but not in Elisp.

In the following I present a function my-string-float-p that returns t if the whole string is read as a floating point number by the Elisp reader.

One can interpret the first object in the string as lisp by read and test this object with floatp.

If read has gobbled all characters from the string that is the only thing represented by the string.

(defun my-string-float-p (str)
  "Non-nil if string STR represents a floating point number."
  (with-temp-buffer
    (insert str)
    (goto-char (point-min))
    (condition-case nil
        (and (floatp (read (current-buffer)))
             (eobp))
        (error nil))))

Test suite:

(my-string-float-p "x")
nil
(my-string-float-p "0")
nil
(my-string-float-p "0.0")
t
(my-string-float-p "8.3")
t
(my-string-float-p "0.1Hello")
nil
(my-string-float-p "0.1 Hello")
nil
(my-string-float-p "(")
nil
(my-string-float-p ")")
nil
Tobias
  • 33,167
  • 1
  • 37
  • 77
  • 1
    (defun f (s) (floatp (read s))) does the same thing for a string arg, no? At least for your test suite it seems to. – Drew Jul 09 '18 at 14:55
  • @Drew I added a test case (my-string-float-p "0.1 Hello") which does not return the expected nil with (f "0.1 Hello") and your (defun f (s) (floatp (read s))). – Tobias Jul 09 '18 at 15:00
2

I think string-to-number is usable here. It has the unfortunate property that it returns 0 for non-numeric strings (an option to return nil would seem sensible, especially as that's what its helper actually does); however 0 is not a float, so...

(defun my-string-float-p (str)
  "Non-nil if string STR represents a floating point number."
  (floatp (string-to-number str)))

(my-string-float-p "x")
nil

(my-string-float-p "0")
nil

(my-string-float-p "0.0")
t
phils
  • 50,977
  • 3
  • 79
  • 122
  • 3
    my-string-float-p gives t for (my-string-float-p "0.1Hello"). Is that intended behavior? – Tobias Jul 09 '18 at 07:51
  • 2
    Right, (string-to-number "0.1Hello") returns 0.1. It's documented (trailing chars are ignored), so it's "intended" in that respect. Whether it's useful behaviour rather depends on your use-case. Thanks for pointing it out. – phils Jul 09 '18 at 10:20
  • for my use case its ok – american-ninja-warrior Jul 09 '18 at 12:26
1
(defun string-float-p (str)
  "Non-nil if string STR represents a floating point number."
  (let ((rd  (read-from-string str)))
    (and (floatp (car rd))  (eq (cdr rd) (length str)))))
Drew
  • 77,472
  • 10
  • 114
  • 243
  • Protection against reading strings with erroneous lisp is also necessary (condition-case nil ... (error nil)). – Tobias Jul 09 '18 at 18:59
  • A similar effect would be possible with (let ((rd (read (concat "(" str ")")))) (and (floatp (car rd)) (null (cdr rd)))). That version would ignore spaces at front and tail of str. – Tobias Jul 09 '18 at 19:02