all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* How to read an integer from the minibuffer
@ 2021-11-11  4:53 Marcin Borkowski
  2021-11-11  5:11 ` Po Lu
                   ` (4 more replies)
  0 siblings, 5 replies; 55+ messages in thread
From: Marcin Borkowski @ 2021-11-11  4:53 UTC (permalink / raw)
  To: Help Gnu Emacs mailing list

Hi all,

I'd like to read an integer (or something else e.g. matching a regex)
from a minibuffer.  Basically, I'm after a version of `read-string', but
either allowing only some characters, or accepting only input matching
some regex (possibly both).

How do I do that?  One way would be to use `read-from-minibuffer' with
a suitable keymap, but that seems slightly low-level.  If that is the
way to go, is there a good way to set up a keymap so that nothing except
some specified characters are self-inserting?  IOW, is `suppress-keymap'
the way to go or is there some other way?

TIA,

-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
@ 2021-11-11  5:11 ` Po Lu
  2021-11-11  7:18   ` Marcin Borkowski
  2021-11-11  6:27 ` Emanuel Berg via Users list for the GNU Emacs text editor
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 55+ messages in thread
From: Po Lu @ 2021-11-11  5:11 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: Help Gnu Emacs mailing list

Marcin Borkowski <mbork@mbork.pl> writes:

> I'd like to read an integer (or something else e.g. matching a regex)
> from a minibuffer.  Basically, I'm after a version of `read-string', but
> either allowing only some characters, or accepting only input matching
> some regex (possibly both).
>
> How do I do that?  One way would be to use `read-from-minibuffer' with
> a suitable keymap, but that seems slightly low-level.  If that is the
> way to go, is there a good way to set up a keymap so that nothing except
> some specified characters are self-inserting?  IOW, is `suppress-keymap'
> the way to go or is there some other way?
>
> TIA,

Perhaps you're looking for `read-number'?



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
  2021-11-11  5:11 ` Po Lu
@ 2021-11-11  6:27 ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-11 10:25 ` Gregory Heytings
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-11  6:27 UTC (permalink / raw)
  To: help-gnu-emacs

Marcin Borkowski wrote:

> I'd like to read an integer (or something else e.g.
> matching a regex) from a minibuffer. Basically, I'm after
> a version of `read-string', but either allowing only some
> characters, or accepting only input matching some regex
> (possibly both).

Hm ... interesting

(require 'cl-lib)

(let ((n))
  (cl-loop until (progn
                   (setq n (read-number "integer: " 1))
                   (integerp n) ))
  n)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  5:11 ` Po Lu
@ 2021-11-11  7:18   ` Marcin Borkowski
  2021-11-12  7:21     ` Yuri Khan
  0 siblings, 1 reply; 55+ messages in thread
From: Marcin Borkowski @ 2021-11-11  7:18 UTC (permalink / raw)
  To: Po Lu; +Cc: Help Gnu Emacs mailing list


On 2021-11-11, at 06:11, Po Lu <luangruo@yahoo.com> wrote:

> Marcin Borkowski <mbork@mbork.pl> writes:
>
>> I'd like to read an integer (or something else e.g. matching a regex)
>> from a minibuffer.  Basically, I'm after a version of `read-string', but
>> either allowing only some characters, or accepting only input matching
>> some regex (possibly both).
>>
>> How do I do that?  One way would be to use `read-from-minibuffer' with
>> a suitable keymap, but that seems slightly low-level.  If that is the
>> way to go, is there a good way to set up a keymap so that nothing except
>> some specified characters are self-inserting?  IOW, is `suppress-keymap'
>> the way to go or is there some other way?
>>
>> TIA,
>
> Perhaps you're looking for `read-number'?

Thanks, that is nice, but not very general.  Another value I want to
read is a time in the hh:mm format, for example.

Thanks anyway,

-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
  2021-11-11  5:11 ` Po Lu
  2021-11-11  6:27 ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-11 10:25 ` Gregory Heytings
  2021-11-11 10:28   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-11 11:17 ` Gregory Heytings
  2021-11-12  6:21 ` Marcin Borkowski
  4 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-11 10:25 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs


>
> I'd like to read an integer (or something else e.g. matching a regex) 
> from a minibuffer.  Basically, I'm after a version of `read-string', but 
> either allowing only some characters, or accepting only input matching 
> some regex (possibly both).
>
> How do I do that?  One way would be to use `read-from-minibuffer' with a 
> suitable keymap, but that seems slightly low-level.  If that is the way 
> to go, is there a good way to set up a keymap so that nothing except 
> some specified characters are self-inserting?  IOW, is `suppress-keymap' 
> the way to go or is there some other way?
>

(defun restricted-read-from-minibuffer (prompt allowed-chars)
   "Read a string from the minibuffer, prompting with PROMPT.
The only allowed characters are those in the string ALLOWED-CHARS."
   (let ((m (make-keymap)))
     (define-key m [t] #'ignore)
     (define-key m (kbd "RET") #'exit-minibuffer)
     (define-key m (kbd "<return>") #'exit-minibuffer)
     (define-key m (kbd "C-j") #'exit-minibuffer)
     (define-key m (kbd "C-g") #'abort-minibuffers)
     (dolist (c (split-string allowed-chars "" t))
       (define-key m c #'self-insert-command))
     (read-from-minibuffer prompt nil m)))



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 10:25 ` Gregory Heytings
@ 2021-11-11 10:28   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-11 11:00     ` Gregory Heytings
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-11 10:28 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

> (defun restricted-read-from-minibuffer (prompt allowed-chars)
>   "Read a string from the minibuffer, prompting with PROMPT.
> The only allowed characters are those in the string ALLOWED-CHARS."
>   (let ((m (make-keymap)))
>     (define-key m [t] #'ignore)
>     (define-key m (kbd "RET") #'exit-minibuffer)
>     (define-key m (kbd "<return>") #'exit-minibuffer)
>     (define-key m (kbd "C-j") #'exit-minibuffer)
>     (define-key m (kbd "C-g") #'abort-minibuffers)
>     (dolist (c (split-string allowed-chars "" t))
>       (define-key m c #'self-insert-command))
>     (read-from-minibuffer prompt nil m)))

(read-number "try input a string instead: ")

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 10:28   ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-11 11:00     ` Gregory Heytings
  2021-11-11 13:20       ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-11 11:00 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: help-gnu-emacs


>> (defun restricted-read-from-minibuffer (prompt allowed-chars)
>>   "Read a string from the minibuffer, prompting with PROMPT.
>> The only allowed characters are those in the string ALLOWED-CHARS."
>>   (let ((m (make-keymap)))
>>     (define-key m [t] #'ignore)
>>     (define-key m (kbd "RET") #'exit-minibuffer)
>>     (define-key m (kbd "<return>") #'exit-minibuffer)
>>     (define-key m (kbd "C-j") #'exit-minibuffer)
>>     (define-key m (kbd "C-g") #'abort-minibuffers)
>>     (dolist (c (split-string allowed-chars "" t))
>>       (define-key m c #'self-insert-command))
>>     (read-from-minibuffer prompt nil m)))
>
> (read-number "try input a string instead: ")
>

(read-number "Try input a time in hh:mm format: ")



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
                   ` (2 preceding siblings ...)
  2021-11-11 10:25 ` Gregory Heytings
@ 2021-11-11 11:17 ` Gregory Heytings
  2021-11-11 13:39   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12  6:21 ` Marcin Borkowski
  4 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-11 11:17 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: help-gnu-emacs


>
> I'd like to read an integer (or something else e.g. matching a regex) 
> from a minibuffer.  Basically, I'm after a version of `read-string', but 
> either allowing only some characters, or accepting only input matching 
> some regex (possibly both).
>
> How do I do that?  One way would be to use `read-from-minibuffer' with a 
> suitable keymap, but that seems slightly low-level.  If that is the way 
> to go, is there a good way to set up a keymap so that nothing except 
> some specified characters are self-inserting?  IOW, is `suppress-keymap' 
> the way to go or is there some other way?
>

Another way:

(defun restricted-read-from-minibuffer (prompt regexp)
   "Read a string matching REGEXP from the minibuffer, prompting with PROMPT."
   (let ((s nil))
     (while (progn
 	     (setq s (read-from-minibuffer prompt))
 	     (unless (string-match regexp s)
 	       (message "Unexpected input.")
 	       (sit-for 1)
 	       t)))
     s))



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 11:00     ` Gregory Heytings
@ 2021-11-11 13:20       ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-11 13:20 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>>> (defun restricted-read-from-minibuffer (prompt allowed-chars)
>>>   "Read a string from the minibuffer, prompting with PROMPT.
>>> The only allowed characters are those in the string ALLOWED-CHARS."
>>>   (let ((m (make-keymap)))
>>>     (define-key m [t] #'ignore)
>>>     (define-key m (kbd "RET") #'exit-minibuffer)
>>>     (define-key m (kbd "<return>") #'exit-minibuffer)
>>>     (define-key m (kbd "C-j") #'exit-minibuffer)
>>>     (define-key m (kbd "C-g") #'abort-minibuffers)
>>>     (dolist (c (split-string allowed-chars "" t))
>>>       (define-key m c #'self-insert-command))
>>>     (read-from-minibuffer prompt nil m)))
>>
>> (read-number "try input a string instead: ")
>
> (read-number "Try input a time in hh:mm format: ")

`read-number' doesn't disallow any input, it checks after.

  (unless (numberp n)
    (message "Please enter a number.") ; ...

/usr/local/share/emacs/29.0.50/lisp/subr.el lines 2873-2874

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 11:17 ` Gregory Heytings
@ 2021-11-11 13:39   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-11 14:30     ` Gregory Heytings
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-11 13:39 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>> I'd like to read an integer (or something else e.g.
>> matching a regex) from a minibuffer. Basically, I'm after
>> a version of `read-string', but either allowing only some
>> characters, or accepting only input matching some regex
>> (possibly both).
>>
>> How do I do that? One way would be to use
>> `read-from-minibuffer' with a suitable keymap, but that
>> seems slightly low-level. If that is the way to go, is
>> there a good way to set up a keymap so that nothing except
>> some specified characters are self-inserting? IOW, is
>> `suppress-keymap' the way to go or is there some other way?
>>
>
> Another way:
>
> (defun restricted-read-from-minibuffer (prompt regexp)
>   "Read a string matching REGEXP from the minibuffer, prompting with PROMPT."
>   (let ((s nil))
>     (while (progn
> 	     (setq s (read-from-minibuffer prompt))
> 	     (unless (string-match regexp s)
> 	       (message "Unexpected input.")
> 	       (sit-for 1)
> 	       t)))
>     s))

Cool (honestly). But do show how to use that to read an
integer and only an integer ...

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 13:39   ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-11 14:30     ` Gregory Heytings
  2021-11-12  0:28       ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-11 14:30 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: help-gnu-emacs


>
> Cool (honestly). But do show how to use that to read an integer and only 
> an integer ...
>

You mean, how these two answers can be combined?

(defun restricted-read-from-minibuffer (prompt regexp &optional allowed-chars)
   "Read a string from the minibuffer, with additional constraints.
If the input does not match REGEXP, read a string again.
If ALLOWED-CHARS is a string, the only allowed characters are those in
that string."
   (let ((map nil)
 	(string nil))
     (when (stringp allowed-chars)
       (let ((m (make-keymap)))
 	(define-key m [t]
 		    (lambda ()
 		      (interactive)
 		      (message "Character not allowed")))
 	(define-key m (kbd "RET") #'exit-minibuffer)
 	(define-key m (kbd "<return>") #'exit-minibuffer)
 	(define-key m (kbd "C-j") #'exit-minibuffer)
 	(define-key m (kbd "C-g") #'abort-minibuffers)
 	(dolist (c (split-string allowed-chars "" t))
 	  (define-key m c #'self-insert-command))
 	(setq map m)))
     (while (progn
 	     (setq string (read-from-minibuffer prompt nil map))
 	     (when regexp
 	       (unless (string-match regexp string nil t)
 		 (message "Unexpected input.")
 		 (sit-for 1)
 		 t))))
     string))

With this,

(restricted-read-from-minibuffer "Integer? " "^[0-9][0-9]*$" "0123456789")

will read "an integer and only an integer".  And you can wrap it into a 
string-to-number to get the integer itself.

(BTW, it seems that there's no way in Elisp to "expand" a regexp charset, 
e.g. "[0-9]" into "0123456789".  That would make the ALLOWED-CHARS 
argument easier to type in.)



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11 14:30     ` Gregory Heytings
@ 2021-11-12  0:28       ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12  0:37         ` Gregory Heytings
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12  0:28 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>> Cool (honestly). But do show how to use that to read an
>> integer and only an integer ...
>
> You mean, how these two answers can be combined?

Nope, I don't like the first solution since it disallows
certain input chars, that feels like the shell would disallow
-j after 'ls' just because there is no such option to ls(1)
... i.e., that doesn't feel good.

This time try it for real:

  (read-number "try enter a string: ")

That's better.

Rather, I meant show how to use the second solution to solve
the OPs example, i.e. to read an integer and only an integer.

> (defun restricted-read-from-minibuffer (prompt regexp &optional allowed-chars)
>   "Read a string from the minibuffer, with additional constraints.
> If the input does not match REGEXP, read a string again.
> If ALLOWED-CHARS is a string, the only allowed characters are those in
> that string."
>   (let ((map nil)
> 	(string nil))
>     (when (stringp allowed-chars)
>       (let ((m (make-keymap)))
> 	(define-key m [t]
> 		    (lambda ()
> 		      (interactive)
> 		      (message "Character not allowed")))
> 	(define-key m (kbd "RET") #'exit-minibuffer)
> 	(define-key m (kbd "<return>") #'exit-minibuffer)
> 	(define-key m (kbd "C-j") #'exit-minibuffer)
> 	(define-key m (kbd "C-g") #'abort-minibuffers)
> 	(dolist (c (split-string allowed-chars "" t))
> 	  (define-key m c #'self-insert-command))
> 	(setq map m)))
>     (while (progn
> 	     (setq string (read-from-minibuffer prompt nil map))
> 	     (when regexp
> 	       (unless (string-match regexp string nil t)
> 		 (message "Unexpected input.")
> 		 (sit-for 1)
> 		 t))))
>     string))
>
> With this,
>
> (restricted-read-from-minibuffer "Integer? " "^[0-9][0-9]*$" "0123456789")

I get

  if: Wrong number of arguments: string-match, 4

but that's a minor bug I suspect ...

You can also write the integer regexp like below

  (string-match "^[0-9]\\{1,\\}$" "99") ; 0, The Great One
  (string-match "^[0-9]\\{1,\\}$" "88") ; 0, Big Eric

or maybe "^[1-9][0-9]*$" ...

> will read "an integer and only an integer".  And you can wrap
> it into a string-to-number to get the integer itself.
>
> (BTW, it seems that there's no way in Elisp to "expand"
> a regexp charset, e.g. "[0-9]" into "0123456789".  That would
> make the ALLOWED-CHARS argument easier to type in.)

There is such a package, xr - the reverse of rx, LOL :)

  https://elpa.gnu.org/packages/xr.html

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:28       ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12  0:37         ` Gregory Heytings
  2021-11-12  0:41           ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-12  0:37 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: help-gnu-emacs


>
> Rather, I meant show how to use the second solution to solve
> the OPs example, i.e. to read an integer and only an integer.
>

Just use

(restricted-read-from-minibuffer "Integer? " "^[0-9][0-9]*$")

instead of

(restricted-read-from-minibuffer "Integer? " "^[0-9][0-9]*$" "0123456789")

>
> I get if: Wrong number of arguments: string-match, 4
>

The fourth argument is new in Emacs 29, indeed.

>> (BTW, it seems that there's no way in Elisp to "expand" a regexp 
>> charset, e.g. "[0-9]" into "0123456789".  That would make the 
>> ALLOWED-CHARS argument easier to type in.)
>
> There is such a package, xr - the reverse of rx, LOL :)
>
>  https://elpa.gnu.org/packages/xr.html
>

Apparently it doesn't do what I want here, namely converting "[0-9]" into 
"0123456789", "[0-9a-f]" into "0123456789abcdef", and so forth.



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:37         ` Gregory Heytings
@ 2021-11-12  0:41           ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12  0:52             ` Gregory Heytings
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12  0:41 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>> Rather, I meant show how to use the second solution to
>> solve the OPs example, i.e. to read an integer and only
>> an integer.
>
> Just use
>
> (restricted-read-from-minibuffer "Integer? " "^[0-9][0-9]*$")

Same

  if: Wrong number of arguments: string-match, 4

> The fourth argument is new in Emacs 29, indeed.

GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, cairo version
1.16.0) of 2021-10-04

>>> (BTW, it seems that there's no way in Elisp to "expand"
>>> a regexp charset, e.g. "[0-9]" into "0123456789".
>>> That would make the ALLOWED-CHARS argument easier to
>>> type in.)
>>
>> There is such a package, xr - the reverse of rx, LOL :)
>>
>>   https://elpa.gnu.org/packages/xr.html
>
> Apparently it doesn't do what I want here, namely converting
> "[0-9]" into "0123456789", "[0-9a-f]" into
> "0123456789abcdef", and so forth.

I think it can!

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:41           ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12  0:52             ` Gregory Heytings
  2021-11-12  0:57               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12  1:09               ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 2 replies; 55+ messages in thread
From: Gregory Heytings @ 2021-11-12  0:52 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: help-gnu-emacs


>> The fourth argument is new in Emacs 29, indeed.
>
> GNU Emacs 29.0.50 (build 1, x86_64-pc-linux-gnu, cairo version 1.16.0) 
> of 2021-10-04
>

It was added on 2021-10-07 ;-)

>> Apparently it doesn't do what I want here, namely converting "[0-9]" 
>> into "0123456789", "[0-9a-f]" into "0123456789abcdef", and so forth.
>
> I think it can!
>

Please show me how...



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:52             ` Gregory Heytings
@ 2021-11-12  0:57               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 19:05                 ` Jean Louis
  2021-11-12  1:09               ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12  0:57 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>>> Apparently it doesn't do what I want here, namely
>>> converting "[0-9]" into "0123456789", "[0-9a-f]" into
>>> "0123456789abcdef", and so forth.
>>
>> I think it can!
>
> Please show me how...

First here is another version of "read-integer" ...

We see a problem BTW that `string-to-number' returns 0
on error!

  (string-to-number "Number Nighty Nine") ; 0

Anyway ...

(require 'cl-lib)

(defun read-integer ()
  (let ((str)
        (str-number)
        (n) )
    (cl-loop until (progn
                     (setq str (read-string "integer: "))
                     (if (string= str "0")
                         (setq n 0)
                       (setq str-number (string-to-number str))
                       (unless (= str-number 0)
                         (setq n str-number) ))
                     (integerp n)) )
    n) )

;; (read-integer)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:52             ` Gregory Heytings
  2021-11-12  0:57               ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12  1:09               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12  1:12                 ` Gregory Heytings
  1 sibling, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12  1:09 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>>> Apparently it doesn't do what I want here, namely
>>> converting "[0-9]" into "0123456789", "[0-9a-f]" into
>>> "0123456789abcdef", and so forth.
>>
>> I think it can!
>
> Please show me how

I don't know but you realize it must be possible since
otherwise how can it be used ...

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  1:09               ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12  1:12                 ` Gregory Heytings
  2021-11-12  3:07                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Gregory Heytings @ 2021-11-12  1:12 UTC (permalink / raw)
  To: Emanuel Berg; +Cc: help-gnu-emacs


>>>> Apparently it doesn't do what I want here, namely converting "[0-9]" 
>>>> into "0123456789", "[0-9a-f]" into "0123456789abcdef", and so forth.
>>>
>>> I think it can!
>>
>> Please show me how
>
> I don't know but you realize it must be possible since otherwise how can 
> it be used ...
>

Of course it's possible; what I said is that there's AFAIK no predefined 
function in Elisp that does it.



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  1:12                 ` Gregory Heytings
@ 2021-11-12  3:07                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12  3:07 UTC (permalink / raw)
  To: help-gnu-emacs

Gregory Heytings wrote:

>>>>> Apparently it doesn't do what I want here, namely
>>>>> converting "[0-9]" into "0123456789", "[0-9a-f]" into
>>>>> "0123456789abcdef", and so forth.
>>>>
>>>> I think it can!
>>>
>>> Please show me how
>>
>> I don't know but you realize it must be possible since
>> otherwise how can it be used ...
>
> Of course it's possible; what I said is that there's AFAIK no
> predefined function in Elisp that does it.

if it is possible there's a function ...

https://www.youtube.com/watch?v=YdXQJS3Yv0Y

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
                   ` (3 preceding siblings ...)
  2021-11-11 11:17 ` Gregory Heytings
@ 2021-11-12  6:21 ` Marcin Borkowski
  2021-11-16  7:52   ` Emanuel Berg via Users list for the GNU Emacs text editor
  4 siblings, 1 reply; 55+ messages in thread
From: Marcin Borkowski @ 2021-11-12  6:21 UTC (permalink / raw)
  To: Help Gnu Emacs mailing list

Ok,

thanks for all your answers!

Best,
mbork




On 2021-11-11, at 05:53, Marcin Borkowski <mbork@mbork.pl> wrote:

> Hi all,
>
> I'd like to read an integer (or something else e.g. matching a regex)
> from a minibuffer.  Basically, I'm after a version of `read-string', but
> either allowing only some characters, or accepting only input matching
> some regex (possibly both).
>
> How do I do that?  One way would be to use `read-from-minibuffer' with
> a suitable keymap, but that seems slightly low-level.  If that is the
> way to go, is there a good way to set up a keymap so that nothing except
> some specified characters are self-inserting?  IOW, is `suppress-keymap'
> the way to go or is there some other way?
>
> TIA,


-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-11  7:18   ` Marcin Borkowski
@ 2021-11-12  7:21     ` Yuri Khan
  2021-11-13  6:59       ` Marcin Borkowski
  2021-11-13  7:33       ` Jean Louis
  0 siblings, 2 replies; 55+ messages in thread
From: Yuri Khan @ 2021-11-12  7:21 UTC (permalink / raw)
  To: Marcin Borkowski; +Cc: Po Lu, Help Gnu Emacs mailing list

On Thu, 11 Nov 2021 at 14:19, Marcin Borkowski <mbork@mbork.pl> wrote:

> >> How do I do that?  One way would be to use `read-from-minibuffer' with
> >> a suitable keymap, but that seems slightly low-level.  If that is the
> >> way to go, is there a good way to set up a keymap so that nothing except
> >> some specified characters are self-inserting?  IOW, is `suppress-keymap'
> >> the way to go or is there some other way?
> >
> > Perhaps you're looking for `read-number'?
>
> Thanks, that is nice, but not very general.  Another value I want to
> read is a time in the hh:mm format, for example.

There are lots of examples out there of form controls trying to
prevent the user from entering invalid data, and they demonstrate many
things you can get wrong while implementing one.

A form control for integer numbers only permits typing digits (as you
initially asked). Now the user cannot enter -42.

Okay, after a bug report and a fix, the control now permits the minus
sign. But the control validates the entry after every keypress, so, as
soon as the user starts typing, they are presented with an error
message, “‘-’ is not a valid integer”. Well, duh, I just started
typing, let me finish it!

My bank’s money transfer web form’s amount field filters keypresses to
only allow digits. One, I cannot paste a number I copied from an
invoice opened elsewhere. Two, I cannot press Ctrl+L to activate my
browser’s address bar, or switch to another tab with Ctrl+PgUp,
Ctrl+PgDn, or Alt+[1…9]. Three, I can’t move my cursor if I
inadvertently skip or mistype a digit, e.g., to correct a 1000 to
15000, I cannot type ‘← ← ← 5’, I have to type ‘backspace backspace
backspace 5 0 0 0’.

A license activation input box in a proprietary software installer
wants a string of 20 semi-random letters. Since no one can reliably
enter that in one go, it splits those 20 letters into 4 groups of 5
and presents them as separate input boxes. As a courtesy to the user,
as soon as 5 letters are typed in the first box, the cursor
automatically moves to the second box. However, if you mistype the
last of those 5 letters, Backspace does not delete it, because
technically you’re in the second box and it’s technically empty,
there’s nothing to delete. Also, you can’t paste the whole 20-letter
code in one go, because the first box is limited to 5 letters.

A bank money transfer is confirmed with a 4-digit code that is sent in
an SMS message. As soon as you type the 4th digit, it goes on to
verify the code, without you having to press Enter. However, this
means you cannot immediately correct a mistyped 4th digit; you get a
“verification failed” message first.


Guideline: Perform input validation only after the user has indicated
they are finished with data entry.



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  0:57               ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12 19:05                 ` Jean Louis
  2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-12 19:05 UTC (permalink / raw)
  To: help-gnu-emacs

* Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-12 03:58]:
> Gregory Heytings wrote:
> 
> >>> Apparently it doesn't do what I want here, namely
> >>> converting "[0-9]" into "0123456789", "[0-9a-f]" into
> >>> "0123456789abcdef", and so forth.
> >>
> >> I think it can!
> >
> > Please show me how...
> 
> First here is another version of "read-integer" ...
> 
> We see a problem BTW that `string-to-number' returns 0
> on error!

That problem I have solved in rcd-utilities.el with:

(defun string-is-number-p (s)
  "Return number only if string is pure number, otherwise NIL."
  (let ((s (string-trim s)))
    (cond ((seq-empty-p s) nil)
	  ((string-match "[^0123456789\\.]" s) nil)
	  ((numberp (string-to-number s)) (string-to-number s)))))

-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 19:05                 ` Jean Louis
@ 2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 19:55                     ` Jean Louis
                                       ` (2 more replies)
  0 siblings, 3 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12 19:25 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

>> We see a problem BTW that `string-to-number' returns 0
>> on error!
>
> That problem I have solved in rcd-utilities.el with:
>
> (defun string-is-number-p (s)
>   "Return number only if string is pure number,
> otherwise NIL."

  A number is said to be pure if

    1. It has even number of digits.
    2. All the digits are either 4 or 5.
    3. And the number is a palindrome.

  First few pure numbers are 44, 55, 4444, 4554, 5445, 5555 ... [1]

Also the familiar docstring functional parameter issue.

>   (let ((s (string-trim s)))
>     (cond ((seq-empty-p s) nil)
> 	  ((string-match "[^0123456789\\.]" s) nil)

Use a char class or an interval?

> 	  ((numberp (string-to-number s)) (string-to-number s)))))

(string-is-number-p "-0")
(string-is-number-p "-5.3")

[1] https://www.geeksforgeeks.org/find-the-first-n-pure-numbers/

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12 19:55                     ` Jean Louis
  2021-11-12 21:14                       ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 19:56                     ` Jean Louis
  2021-11-12 20:02                     ` Jean Louis
  2 siblings, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-12 19:55 UTC (permalink / raw)
  To: help-gnu-emacs

* Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-12 22:26]:
> Jean Louis wrote:
> 
> >> We see a problem BTW that `string-to-number' returns 0
> >> on error!
> >
> > That problem I have solved in rcd-utilities.el with:
> >
> > (defun string-is-number-p (s)
> >   "Return number only if string is pure number,
> > otherwise NIL."
> 
>   A number is said to be pure if
> 
>     1. It has even number of digits.
>     2. All the digits are either 4 or 5.
>     3. And the number is a palindrome.

Should I say "actual number"?


-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 19:55                     ` Jean Louis
@ 2021-11-12 19:56                     ` Jean Louis
  2021-11-12 20:02                     ` Jean Louis
  2 siblings, 0 replies; 55+ messages in thread
From: Jean Louis @ 2021-11-12 19:56 UTC (permalink / raw)
  To: help-gnu-emacs

* Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-12 22:26]:
> (string-is-number-p "-0")
> (string-is-number-p "-5.3")

Bad, so propose regexp.


-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 19:55                     ` Jean Louis
  2021-11-12 19:56                     ` Jean Louis
@ 2021-11-12 20:02                     ` Jean Louis
  2021-11-12 20:24                       ` tomas
  2 siblings, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-12 20:02 UTC (permalink / raw)
  To: help-gnu-emacs

Improved check for number:

(defun string-is-number-p (s)
  "Return number only if string is actual number, otherwise NIL."
  (let* ((s (string-trim s)))
    (cond ((seq-empty-p s) nil)
	  ((string-match "[^0123456789\\.-]" s) nil)
	  ((string-match "-" s 1) nil)
	  ((numberp (string-to-number s)) (string-to-number s)))))

(string-is-number-p "-0.1") ⇒ -0.1
(string-is-number-p "0.1") ⇒ 0.1
(string-is-number-p "0.1-") ⇒ nil
(string-is-number-p "  1 ") ⇒ 1
(string-is-number-p " a 1 ") ⇒ nil


-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 20:02                     ` Jean Louis
@ 2021-11-12 20:24                       ` tomas
  2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-13  6:36                         ` Jean Louis
  0 siblings, 2 replies; 55+ messages in thread
From: tomas @ 2021-11-12 20:24 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 499 bytes --]

On Fri, Nov 12, 2021 at 11:02:10PM +0300, Jean Louis wrote:
> Improved check for number:
> 
> (defun string-is-number-p (s)
>   "Return number only if string is actual number, otherwise NIL."
>   (let* ((s (string-trim s)))
>     (cond ((seq-empty-p s) nil)
> 	  ((string-match "[^0123456789\\.-]" s) nil)
> 	  ((string-match "-" s 1) nil)
> 	  ((numberp (string-to-number s)) (string-to-number s)))))

Why not simply numberp?

  (and (numberp s) (string-to-number s))

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 19:55                     ` Jean Louis
@ 2021-11-12 21:14                       ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-13  6:37                         ` Jean Louis
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12 21:14 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

> Should I say "actual number"?

It depends:

  complex    C = ... -3 + 2i, 0, 1 + 3i ...                          
  composite      4, 6, 8, 9, 10, 12 ...
  integers   Z = ... -3, -2, -1, 0, 1, 2, 3 ...
  irrational F = ... \pi, \sqrt{2}, 0.121221222 ...
  natural    N = 1, 2, 3, 4 ...
  prime      P = 2, 3, 5, 7, 11, 13, 17 ...
  rational   Q = -\frac{1}{2}, 0.33333 ... \frac{5}{2}, \frac{11}{10} ... 
  real       R = ... -3, -1, 0, \frac{1}{5}, 1.1, \sqrt{2}, 2, 3, \pi ...
  whole      W = 0, 1, 2, 3, 4 ...

https://davenport.libguides.com/math-skills-overview/basic-operations/sets

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 20:24                       ` tomas
@ 2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 21:30                           ` tomas
  2021-11-13  6:46                           ` Jean Louis
  2021-11-13  6:36                         ` Jean Louis
  1 sibling, 2 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12 21:15 UTC (permalink / raw)
  To: help-gnu-emacs

tomas wrote:

> Why not simply numberp?
>
>   (and (numberp s) (string-to-number s))

King :)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-12 21:30                           ` tomas
  2021-11-12 21:34                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-13  6:46                           ` Jean Louis
  1 sibling, 1 reply; 55+ messages in thread
From: tomas @ 2021-11-12 21:30 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 330 bytes --]

On Fri, Nov 12, 2021 at 10:15:28PM +0100, Emanuel Berg via Users list for the GNU Emacs text editor wrote:
> tomas wrote:
> 
> > Why not simply numberp?
> >
> >   (and (numberp s) (string-to-number s))
> 
> King :)

I have some anarchist tendencies. That would make me double-personality,
right?

;-)

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 21:30                           ` tomas
@ 2021-11-12 21:34                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-12 21:34 UTC (permalink / raw)
  To: help-gnu-emacs

tomas wrote:

>>> Why not simply numberp?
>>>
>>>   (and (numberp s) (string-to-number s))
>> 
>> King :)
>
> I have some anarchist tendencies.

Me too ...

  https://dataswamp.org/~incal/blog/

> That would make me double-personality, right?

*multidimensional

2006 movie dedicated tomas:

  https://www.imdb.com/title/tt7972356/

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 20:24                       ` tomas
  2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-13  6:36                         ` Jean Louis
  2021-11-13  8:17                           ` tomas
  1 sibling, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-13  6:36 UTC (permalink / raw)
  To: tomas; +Cc: help-gnu-emacs

* tomas@tuxteam.de <tomas@tuxteam.de> [2021-11-12 23:25]:
> On Fri, Nov 12, 2021 at 11:02:10PM +0300, Jean Louis wrote:
> > Improved check for number:
> > 
> > (defun string-is-number-p (s)
> >   "Return number only if string is actual number, otherwise NIL."
> >   (let* ((s (string-trim s)))
> >     (cond ((seq-empty-p s) nil)
> > 	  ((string-match "[^0123456789\\.-]" s) nil)
> > 	  ((string-match "-" s 1) nil)
> > 	  ((numberp (string-to-number s)) (string-to-number s)))))
> 
> Why not simply numberp?
> 
>   (and (numberp s) (string-to-number s))

(numberp "123") ⇒ nil

It checks if object is number. That is why it is not usable to check
if string is actual number.


-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 21:14                       ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-13  6:37                         ` Jean Louis
  2021-11-16  6:21                           ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-13  6:37 UTC (permalink / raw)
  To: help-gnu-emacs

* Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-13 00:16]:
> Jean Louis wrote:
> 
> > Should I say "actual number"?
> 
> It depends:
> 
>   complex    C = ... -3 + 2i, 0, 1 + 3i ...                          
>   composite      4, 6, 8, 9, 10, 12 ...
>   integers   Z = ... -3, -2, -1, 0, 1, 2, 3 ...
>   irrational F = ... \pi, \sqrt{2}, 0.121221222 ...
>   natural    N = 1, 2, 3, 4 ...
>   prime      P = 2, 3, 5, 7, 11, 13, 17 ...
>   rational   Q = -\frac{1}{2}, 0.33333 ... \frac{5}{2}, \frac{11}{10} ... 
>   real       R = ... -3, -1, 0, \frac{1}{5}, 1.1, \sqrt{2}, 2, 3, \pi ...
>   whole      W = 0, 1, 2, 3, 4 ...
> 
> https://davenport.libguides.com/math-skills-overview/basic-operations/sets

I would just check for those numbers that are accepted by Emacs Lisp.

2i does not evaluate, thus I cannot use that one.

-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-12 21:30                           ` tomas
@ 2021-11-13  6:46                           ` Jean Louis
  2021-11-13  7:32                             ` tomas
  2021-11-16  6:24                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 2 replies; 55+ messages in thread
From: Jean Louis @ 2021-11-13  6:46 UTC (permalink / raw)
  To: help-gnu-emacs

* Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-13 00:21]:
> tomas wrote:
> 
> > Why not simply numberp?
> >
> >   (and (numberp s) (string-to-number s))
> 
> King :)

(let ((s " 123"))
(and (numberp s) (string-to-number s))) ⇒ nil

I do not see how it helps in my use case as I want to ensure that
number in the string is actual number and nothing else.

Example is here:

(let ((s " 123n"))
  (string-to-number "123n")) ⇒ 123

I don't need such cases where I get result "123" from " 123n"
as " 123n" is not number for my use case and I would not like
converting it to close match. 

What is my actual use case? In the Dynamic Knowledge Repository
each elementary object may have its ID, it is usually integer. 

A cursor may be positioned on the word that could be number, but
should not be number with some letters. It should act on
integers, then if search key is pressed it would quickly find the
object. Otherwise it could ask for the query to find the object.

The database will search for any combination of "123n" as this
combination could be part of the email address, but it will
rather start searching for the object ID 123 if there is no "n"
in the combination of letters, it will prefer ID numbers then.

-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  7:21     ` Yuri Khan
@ 2021-11-13  6:59       ` Marcin Borkowski
  2021-11-13  8:43         ` tomas
  2021-11-13  7:33       ` Jean Louis
  1 sibling, 1 reply; 55+ messages in thread
From: Marcin Borkowski @ 2021-11-13  6:59 UTC (permalink / raw)
  To: Yuri Khan; +Cc: Po Lu, Help Gnu Emacs mailing list


On 2021-11-12, at 08:21, Yuri Khan <yuri.v.khan@gmail.com> wrote:

> On Thu, 11 Nov 2021 at 14:19, Marcin Borkowski <mbork@mbork.pl> wrote:
>
>> >> How do I do that?  One way would be to use `read-from-minibuffer' with
>> >> a suitable keymap, but that seems slightly low-level.  If that is the
>> >> way to go, is there a good way to set up a keymap so that nothing except
>> >> some specified characters are self-inserting?  IOW, is `suppress-keymap'
>> >> the way to go or is there some other way?
>> >
>> > Perhaps you're looking for `read-number'?
>>
>> Thanks, that is nice, but not very general.  Another value I want to
>> read is a time in the hh:mm format, for example.
>
> There are lots of examples out there of form controls trying to
> prevent the user from entering invalid data, and they demonstrate many
> things you can get wrong while implementing one.
>
> A form control for integer numbers only permits typing digits (as you
> initially asked). Now the user cannot enter -42.
>
> Okay, after a bug report and a fix, the control now permits the minus
> sign. But the control validates the entry after every keypress, so, as
> soon as the user starts typing, they are presented with an error
> message, “‘-’ is not a valid integer”. Well, duh, I just started
> typing, let me finish it!
>
> My bank’s money transfer web form’s amount field filters keypresses to
> only allow digits. One, I cannot paste a number I copied from an
> invoice opened elsewhere. Two, I cannot press Ctrl+L to activate my
> browser’s address bar, or switch to another tab with Ctrl+PgUp,
> Ctrl+PgDn, or Alt+[1…9]. Three, I can’t move my cursor if I
> inadvertently skip or mistype a digit, e.g., to correct a 1000 to
> 15000, I cannot type ‘← ← ← 5’, I have to type ‘backspace backspace
> backspace 5 0 0 0’.
>
> A license activation input box in a proprietary software installer
> wants a string of 20 semi-random letters. Since no one can reliably
> enter that in one go, it splits those 20 letters into 4 groups of 5
> and presents them as separate input boxes. As a courtesy to the user,
> as soon as 5 letters are typed in the first box, the cursor
> automatically moves to the second box. However, if you mistype the
> last of those 5 letters, Backspace does not delete it, because
> technically you’re in the second box and it’s technically empty,
> there’s nothing to delete. Also, you can’t paste the whole 20-letter
> code in one go, because the first box is limited to 5 letters.
>
> A bank money transfer is confirmed with a 4-digit code that is sent in
> an SMS message. As soon as you type the 4th digit, it goes on to
> verify the code, without you having to press Enter. However, this
> means you cannot immediately correct a mistyped 4th digit; you get a
> “verification failed” message first.
>
>
> Guideline: Perform input validation only after the user has indicated
> they are finished with data entry.

Very good points, thanks.  I am now convinced that I should just
`read-string' - it's also simpler from the coding perspective.

Thanks,

-- 
Marcin Borkowski
http://mbork.pl



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  6:46                           ` Jean Louis
@ 2021-11-13  7:32                             ` tomas
  2021-11-16  6:24                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 55+ messages in thread
From: tomas @ 2021-11-13  7:32 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 899 bytes --]

On Sat, Nov 13, 2021 at 09:46:10AM +0300, Jean Louis wrote:
> * Emanuel Berg via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> [2021-11-13 00:21]:
> > tomas wrote:
> > 
> > > Why not simply numberp?
> > >
> > >   (and (numberp s) (string-to-number s))
> > 
> > King :)
> 
> (let ((s " 123"))
> (and (numberp s) (string-to-number s))) ⇒ nil

So leading spaces are to be ignored, OK. What about trailing
spaces? Exponential notation? Bases other than 10?

I think it's time you specify what a number is /for you/. Then
compare that with what a number is /for numberp/. Then rewrite
your program :)

> Example is here:
> 
> (let ((s " 123n"))
>   (string-to-number "123n")) ⇒ 123

Ah, but (numberp "123n") -> nil, so the and above would work.
Or, perhaps, "123n" should be a number? This is unclear from
what you say. At least to me.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  7:21     ` Yuri Khan
  2021-11-13  6:59       ` Marcin Borkowski
@ 2021-11-13  7:33       ` Jean Louis
  2021-11-16  6:39         ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-13  7:33 UTC (permalink / raw)
  To: Yuri Khan; +Cc: Po Lu, Help Gnu Emacs mailing list

* Yuri Khan <yuri.v.khan@gmail.com> [2021-11-12 10:23]:
> A form control for integer numbers only permits typing digits (as you
> initially asked). Now the user cannot enter -42.

Integers may be negative.

> My bank’s money transfer web form’s amount field filters keypresses to
> only allow digits. One, I cannot paste a number I copied from an
> invoice opened elsewhere. Two, I cannot press Ctrl+L to activate my
> browser’s address bar, or switch to another tab with Ctrl+PgUp,
> Ctrl+PgDn, or Alt+[1…9]. Three, I can’t move my cursor if I
> inadvertently skip or mistype a digit, e.g., to correct a 1000 to
> 15000, I cannot type ‘← ← ← 5’, I have to type ‘backspace backspace
> backspace 5 0 0 0’.

Totally right, the field shall be given to user to freely type and
handle until user presses ENTER. On the other hand certain control is
desired. 

> A bank money transfer is confirmed with a 4-digit code that is sent in
> an SMS message. As soon as you type the 4th digit, it goes on to
> verify the code, without you having to press Enter. However, this
> means you cannot immediately correct a mistyped 4th digit; you get a
> “verification failed” message first.

That is right, those are good example from life.

> Guideline: Perform input validation only after the user has
> indicated they are finished with data entry.

Those examples are not much relevant to Emacs Lisp, it's interface is
quite different to browsers. And it does not have Javascript.

The function `read-number' allows user to enter anything and press
ENTER, upon that program verifies if it is the number or not, and
advises user to enter the number.

That I see as good way to go.

What is not logical to me is to remove the previously entered
information. If user enters "123n", I get message to enter number, but
then it would be useful to provide "123n" again in the same line as to
easier correct it.


-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  6:36                         ` Jean Louis
@ 2021-11-13  8:17                           ` tomas
  2021-11-13  8:44                             ` Jean Louis
  2021-11-16  6:03                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 2 replies; 55+ messages in thread
From: tomas @ 2021-11-13  8:17 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 2955 bytes --]

On Sat, Nov 13, 2021 at 09:36:39AM +0300, Jean Louis wrote:
> * tomas@tuxteam.de <tomas@tuxteam.de> [2021-11-12 23:25]:

[...]

> > Why not simply numberp?
> > 
> >   (and (numberp s) (string-to-number s))
> 
> (numberp "123") ⇒ nil
> 
> It checks if object is number. That is why it is not usable to check
> if string is actual number.

D'oh, you are right. That'd been too easy ;-)

It seems you'll have to go with a regexp, then do string-to-number.
Then, again, you'll have to decide: what subset of Emacs's number
input syntax do you want to implement? Signed/unsigned? Integers?
Floats? Exponential notation? Bases other than 10?

As far as Emacs is concerned, for example, this is a number

  #27r21 -> 55

(this would be 21 in base 27). As is this:

  #b10101 -> 21

That gets interesting once you mix multibase ints and floats: is an
e a digit (in a base greater than 14) or the exponential marker?
(my hunch is that floats & exponential notation is only allowed for
base 10, but more doc reading would be necessary).

Or do you want to set the rules, independently of what Emacs lisp
does? Then you better do that explicitly.

I think you only can get down to work once you've cleared that.

To get you started, here would be a regexp to (roughly) accept
floats:

  ^[+-]?[0-9]*\(?:\.[0-9]+\)\(?:[eE][0-9]+\)$

...the backslashes having to be escaped if you put that into a
string, of course.

Add [[:space:]]* in front (or at the end) of it if you want to
accept leading (or trailing) space.

Here's a "packaged" version for the convenience of your buffer:

  (seq-do
   (lambda (tst)
     (insert
      (format
       "'%s' => %s\n"
       tst
       (string-match-p "^[+-]?[0-9]*\\(?:\\.[0-9]+\\)?\\(?:[eE][0-9]+\\)?$" tst))))
   '("123"
     " 123"
     "123 "
     ""
     "."
     "3.141593"
     ".0"
     "1E12"
     "6.02e23"))

Note a couple of things:
 - note that 0 means success: actually `string-match' is
   returning the position where the match starts, and it can
   only be 0, since our regexp is anchored at the beginning
   (^); on failure it returns nil
 - it does accept an empty string. This comes from the fact that
   we allow the part before the decimal point to be empty (we
   might like to accept ".23"), but also the decimal point and
   all that to its right to be missing ("123" is a nice number,
   after all). This can, of course, be fixed. At the cost of an
   uglier regexp or, alternatively, some post-processing-
 - if you are going to accept leading (and trailing? You didn't
   make your position explicit yet) whitespace, you could put
   the "number part" in a capture group \(...\) so you can
   retrieve it after the match.
 - write a series of tests yourself: this will help you to
   better specify what you want to consider as a number
 - other bases are left as an exercise to the reader ;^)

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  6:59       ` Marcin Borkowski
@ 2021-11-13  8:43         ` tomas
  0 siblings, 0 replies; 55+ messages in thread
From: tomas @ 2021-11-13  8:43 UTC (permalink / raw)
  To: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 1158 bytes --]

On Sat, Nov 13, 2021 at 07:59:49AM +0100, Marcin Borkowski wrote:

[...]
> There are lots of examples out there of form controls trying to
> prevent the user from entering invalid data, and they demonstrate many
> things you can get wrong while implementing one.

I tend to call this "authoritarian software" and I think
it is one of the most preposterous blights our trade has
to offer.

I mean -- the programmers assuming they're smarter than
me, the user, is already somewhat arrogant. But assuming
/their program/ is smarter than their users is downright
insulting.

Now I konw this happens unintentionally (or with the best
of intentions), and it takes some work to "get out" of this
mindset ("don't let the user make /any/ mistake whatsoever").

What does help me, sometimes, is to turn around things and,
for example, consider "let the user make mistakes, but make
it so that they are recoverable".

And, most important: respect your users. Assume they know
best what's good for them, and if, in some situation, you
have evidence to the contrary, help them to find out instead
of telling them.

Usually, this leads to more enjoyable UIs.

Cheers
 - t

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  8:17                           ` tomas
@ 2021-11-13  8:44                             ` Jean Louis
  2021-11-16  6:15                               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16  6:03                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 1 reply; 55+ messages in thread
From: Jean Louis @ 2021-11-13  8:44 UTC (permalink / raw)
  To: tomas; +Cc: help-gnu-emacs

* tomas@tuxteam.de <tomas@tuxteam.de> [2021-11-13 11:18]:
> On Sat, Nov 13, 2021 at 09:36:39AM +0300, Jean Louis wrote:
> > * tomas@tuxteam.de <tomas@tuxteam.de> [2021-11-12 23:25]:
> 
> [...]
> 
> > > Why not simply numberp?
> > > 
> > >   (and (numberp s) (string-to-number s))
> > 
> > (numberp "123") ⇒ nil
> > 
> > It checks if object is number. That is why it is not usable to check
> > if string is actual number.
> 
> D'oh, you are right. That'd been too easy ;-)
> 
> It seems you'll have to go with a regexp, then do string-to-number.
> Then, again, you'll have to decide: what subset of Emacs's number
> input syntax do you want to implement? Signed/unsigned? Integers?
> Floats? Exponential notation? Bases other than 10?

That helped me realize I have to call function different:

(defun string-is-positive-integer-p (s)
  "Return number only if string is positive integer, otherwise
NIL."
  (let* ((s (string-trim s)))
    (cond ((seq-empty-p s) nil)
	  ((string-match "[^0123456789\\.]" s) nil)
	  ((numberp (string-to-number s)) (string-to-number s)))))

-- 
Jean

Take action in Free Software Foundation campaigns:
https://www.fsf.org/campaigns

In support of Richard M. Stallman
https://stallmansupport.org/



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  8:17                           ` tomas
  2021-11-13  8:44                             ` Jean Louis
@ 2021-11-16  6:03                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  6:03 UTC (permalink / raw)
  To: help-gnu-emacs

tomas wrote:

>> It checks if object is number. That is why it is not usable
>> to check if string is actual number.
>
> D'oh, you are right. That'd been too easy ;-)
>
> It seems you'll have to go with a regexp, then do
> string-to-number.

One can use mine initial suggestion. It is a bit complicated -
not the code, but something about it ...

But the actual cause of the confusion is actually
`string-to-number' and this ambiguity:

  (string-to-number "not a number") ; 0
  (string-to-number "0")            ; 0

So ony should start by having string-to-number return nil,
not 0, when the input doesn't make sense!

(defun read-integer ()
  (let ((str)
        (str-number)
        (n) )
    (cl-loop until (progn
                     (setq str (read-string "integer: "))
                     (if (string= str "0")
                         (setq n 0)
                       (setq str-number (string-to-number str))
                       (unless (= str-number 0)
                         (setq n str-number) ))
                     (integerp n)) )
    n) )
;; (read-integer)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  8:44                             ` Jean Louis
@ 2021-11-16  6:15                               ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  6:15 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

> That helped me realize I have to call function different:
>
> (defun string-is-positive-integer-p (s)
>   "Return number only if string is positive integer, otherwise
> NIL."

(checkdoc-current-buffer t)

  Argument ‘s’ should appear (as S) in the doc string

>   (let* ((s (string-trim s)))
>     (cond ((seq-empty-p s) nil)
> 	  ((string-match "[^0123456789\\.]" s) nil)

This regexp should be an interval or char class. (But I'm not
sure this calls for a regexp at all.)

> 	  ((numberp (string-to-number s)) (string-to-number s)))))

This function returns real numbers as well:

  (string-is-positive-integer-p "10.1") ; 10.1

Also, I think the predicates (certain functions with "-p" or
"p" as suffix) should return either t or nil, as in
(numberp 10.1) ; t

Instead, maybe

(defun positive-integer-p (n)
  (and (integerp n)
       (< 0 n) ))
;; (positive-integer-p  1.5) ; nil
;; (positive-integer-p  1)   ; t
;; (positive-integer-p  0)   ; nil
;; (positive-integer-p -1)   ; nil

https://dataswamp.org/~incal/emacs-init/math.el

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  6:37                         ` Jean Louis
@ 2021-11-16  6:21                           ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  6:21 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

>>> Should I say "actual number"?
>> 
>> It depends:
>> 
>>   complex    C = ... -3 + 2i, 0, 1 + 3i ...                          
>>   composite      4, 6, 8, 9, 10, 12 ...
>>   integers   Z = ... -3, -2, -1, 0, 1, 2, 3 ...
>>   irrational F = ... \pi, \sqrt{2}, 0.121221222 ...
>>   natural    N = 1, 2, 3, 4 ...
>>   prime      P = 2, 3, 5, 7, 11, 13, 17 ...
>>   rational   Q = -\frac{1}{2}, 0.33333 ... \frac{5}{2}, \frac{11}{10} ... 
>>   real       R = ... -3, -1, 0, \frac{1}{5}, 1.1, \sqrt{2}, 2, 3, \pi ...
>>   whole      W = 0, 1, 2, 3, 4 ...
>> 
>> https://davenport.libguides.com/math-skills-overview/basic-operations/sets
>
> I would just check for those numbers that are accepted by
> Emacs Lisp.
>
> 2i does not evaluate, thus I cannot use that one.

You can use complex/imaginary numbers in Elisp, e.g.

  (calc-eval "1 + 2i + 3")

Or

  (calcFunc-add 3 '(float 5 0) '(cplx 4 5)) ; (cplx (float 12 0) 5)

See here for more discussion:

  https://stackoverflow.com/questions/28629797/complex-imaginary-numbers-in-elisp

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  6:46                           ` Jean Louis
  2021-11-13  7:32                             ` tomas
@ 2021-11-16  6:24                             ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  6:24 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

> I do not see how it helps in my use case as I want to ensure
> that number in the string is actual number and nothing else.

See this function, it is a workaround.

But the problem is that `string-to-number' returns 0 on "0"
(which is good) but also on "not a number". Don't know what
genious came up with that since it is an obvious
collision/ambiguity.

(defun read-integer ()
  (let ((str)
        (str-number)
        (n) )
    (cl-loop until (progn
                     (setq str (read-string "integer: "))
                     (if (string= str "0")
                         (setq n 0)
                       (setq str-number (string-to-number str))
                       (unless (= str-number 0)
                         (setq n str-number) ))
                     (integerp n)) )
    n) )
;; (read-integer)

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-13  7:33       ` Jean Louis
@ 2021-11-16  6:39         ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16  7:37           ` Yuri Khan
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  6:39 UTC (permalink / raw)
  To: help-gnu-emacs

Jean Louis wrote:

>> A form control for integer numbers only permits typing
>> digits (as you initially asked). Now the user cannot enter
>> -42.
>
> Integers may be negative.

It is better to make _one_ "string-to-number" that makes
sense, then one can easily add extra checks with `integerp'
and `(< 0 n)' and whatever to make it more specific from there...

Here is a start ...

(defun string-to-number-number (str)
  (if (string= str "0")
      0
    (let ((num (string-to-number str)))
      (unless (zerop num)
        num) )))
;; (string-to-number-number "10")
;; (string-to-number-number "1.5")
;; (string-to-number-number "0")
;; (string-to-number-number "-1.5")
;; (string-to-number-number "-10")
;; (string-to-number-number "not a number") ; nil

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16  6:39         ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-16  7:37           ` Yuri Khan
  2021-11-16  8:00             ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Yuri Khan @ 2021-11-16  7:37 UTC (permalink / raw)
  To: Emanuel Berg, help-gnu-emacs

On Tue, 16 Nov 2021 at 13:41, Emanuel Berg via Users list for the GNU
Emacs text editor <help-gnu-emacs@gnu.org> wrote:

> (defun string-to-number-number (str)
>   (if (string= str "0")
>       0
>     (let ((num (string-to-number str)))
>       (unless (zerop num)
>         num) )))
> ;; (string-to-number-number "10")
> ;; (string-to-number-number "1.5")
> ;; (string-to-number-number "0")
> ;; (string-to-number-number "-1.5")
> ;; (string-to-number-number "-10")
> ;; (string-to-number-number "not a number") ; nil

‘string-to-number’ has one more deficiency — it ignores additional
non-digit characters.

M-: (string-to-number "123foo")
⇒ 123 (#o173, #x7b, ?\{)

You cannot build anything strict on such a lax parser.



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-12  6:21 ` Marcin Borkowski
@ 2021-11-16  7:52   ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16  8:05     ` Yuri Khan
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  7:52 UTC (permalink / raw)
  To: help-gnu-emacs

It is in src/data.c lines 2901-2902:

  Lisp_Object val = string_to_number (p, b, 0);
  return NILP (val) ? make_fixnum (0) : val;

The second line (2902) is the problem.

And they explicitely made it be this way ... weird.

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16  7:37           ` Yuri Khan
@ 2021-11-16  8:00             ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  8:00 UTC (permalink / raw)
  To: help-gnu-emacs

Yuri Khan wrote:

>> (defun string-to-number-number (str)
>>   (if (string= str "0")
>>       0
>>     (let ((num (string-to-number str)))
>>       (unless (zerop num)
>>         num) )))
>> ;; (string-to-number-number "10")
>> ;; (string-to-number-number "1.5")
>> ;; (string-to-number-number "0")
>> ;; (string-to-number-number "-1.5")
>> ;; (string-to-number-number "-10")
>> ;; (string-to-number-number "not a number") ; nil
>
> ‘string-to-number’ has one more deficiency — it ignores additional
> non-digit characters.
>
> M-: (string-to-number "123foo") ; 123

I know, I don't know if this is really a problem tho ...

Maybe it can even be thought of as a feature, e.g.

(string-to-number "89.8 cm") ; 89.8

> You cannot build anything strict on such a lax parser.

Don't know how strict we will get but if we identify and patch
the singularities it will be something if not strict then at
least something that is useful.

But sure I think it should be changed in the C source ...

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16  7:52   ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-16  8:05     ` Yuri Khan
  2021-11-16  9:38       ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Yuri Khan @ 2021-11-16  8:05 UTC (permalink / raw)
  To: Emanuel Berg, help-gnu-emacs

On Tue, 16 Nov 2021 at 14:52, Emanuel Berg via Users list for the GNU
Emacs text editor <help-gnu-emacs@gnu.org> wrote:

> And they explicitely made it be this way ... weird.

I was going to suggest piggybacking on the JSON parser, but it has the same bug:

M-: (json-read-from-string "123foo")
⇒ 123 (#o173, #x7b, ?\{)

Fortunately, json-read-from-string is simple enough that you can copy
and modify it:

-(defun json-read-from-string (string)
+(defun json-read-from-string-strict (string)
   "Read the JSON object contained in STRING and return it."
   (with-temp-buffer
     (insert string)
     (goto-char (point-min))
-    (json-read)))
+    (prog1 (json-read)
+      (unless (eobp) (error "Trailing garbage")))))

You still get some whitespace skipping though.



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16  8:05     ` Yuri Khan
@ 2021-11-16  9:38       ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16 11:18         ` Yuri Khan
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16  9:38 UTC (permalink / raw)
  To: help-gnu-emacs

Yuri Khan wrote:

> I was going to suggest piggybacking on the JSON parser, but
> it has the same bug:
>
> M-: (json-read-from-string "123foo")
> ⇒ 123 (#o173, #x7b, ?\{)
>
> Fortunately, json-read-from-string is simple enough that you can copy
> and modify it:
>
> -(defun json-read-from-string (string)
> +(defun json-read-from-string-strict (string)
>    "Read the JSON object contained in STRING and return it."
>    (with-temp-buffer
>      (insert string)
>      (goto-char (point-min))
> -    (json-read)))
> +    (prog1 (json-read)
> +      (unless (eobp) (error "Trailing garbage")))))
>
> You still get some whitespace skipping though.

(defun string-to-number-number (str)
  (let ((s (string-trim str)))
    (if (string-match "^[+-]\\{0,1\\}\\(0+\\|0*\\.0+\\)$" s)
        0
      (let ((num (string-to-number s)))
        (when (and (not (zerop num))
                   (string-match "^[+-]\\{0,1\\}\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)$" s) )
          num) ))))
;; (string-to-number-number " 10")                  ;  10
;; (string-to-number-number "  1.5")                ;   1.5
;; (string-to-number-number " +0")                  ;   0
;; (string-to-number-number "  0")                  ;   0
;; (string-to-number-number " -0.0")                ;   0
;; (string-to-number-number " -1.5")                ;   1.5
;; (string-to-number-number "-10")                  ; -10
;; (string-to-number-number "123this used to work") ; nil
;; (string-to-number-number "not a number")         ; nil

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16  9:38       ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-16 11:18         ` Yuri Khan
  2021-11-16 11:37           ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 55+ messages in thread
From: Yuri Khan @ 2021-11-16 11:18 UTC (permalink / raw)
  To: Emanuel Berg, help-gnu-emacs

On Tue, 16 Nov 2021 at 16:38, Emanuel Berg via Users list for the GNU
Emacs text editor <help-gnu-emacs@gnu.org> wrote:

> (defun string-to-number-number (str)
>   (let ((s (string-trim str)))
>     (if (string-match "^[+-]\\{0,1\\}\\(0+\\|0*\\.0+\\)$" s)
>         0
>       (let ((num (string-to-number s)))
>         (when (and (not (zerop num))
>                    (string-match "^[+-]\\{0,1\\}\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)$" s) )
>           num) ))))

If you’re checking the input string by regexp anyway, you could do
that before calling the parser and simplify to:

    (defun string-to-number-strict (str)
      (if (string-match
"^[+-]?\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)$" s)
          (string-to-number s)
        (error "invalid number")))

(Depending on circumstances, you might want to refine the regexp to
disallow leading zeros unless it is the only digit in the integer
part; and/or allow exponential format. It might also be a good idea to
wrap all that in a ‘save-match-data’.)



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16 11:18         ` Yuri Khan
@ 2021-11-16 11:37           ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16 11:52             ` Yuri Khan
  0 siblings, 1 reply; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16 11:37 UTC (permalink / raw)
  To: help-gnu-emacs

Yuri Khan wrote:

> If you’re checking the input string by regexp anyway, you could do
> that before calling the parser and simplify to:
>
>     (defun string-to-number-strict (str)
>       (if (string-match
> "^[+-]?\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)$" s)
>           (string-to-number s)
>         (error "invalid number")))
>
> Depending on circumstances, you might want to refine the
> regexp to disallow leading zeros unless it is the only digit
> in the integer part; and/or allow exponential format.

Okay, so now we are getting somewhere ... I love the
question mark.

As for disallowing leading zeroes I think it should be as
close to Emacs as possible, eval 00 for example.

(defun string-to-number-number (str)
  (let ((s (string-trim str)))
    (when (string-match
           "^[+-]?\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)$" s)
      (string-to-number s) )))

;; (string-to-number-number " 10")                  ;  10
;; (string-to-number-number "  1.5")                ;   1.5
;; (string-to-number-number " +0")                  ;   0
;; (string-to-number-number "  0")                  ;   0
;; (string-to-number-number " -0.0")                ;  -0.0
;; (string-to-number-number " -1.5")                ;   1.5
;; (string-to-number-number "-10")                  ; -10
;; (string-to-number-number "123this used to work") ; nil
;; (string-to-number-number "NAN")                  ; nil

> It might also be a good idea to wrap all that in
> a ‘save-match-data’.)

What/how do you mean?

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16 11:37           ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-16 11:52             ` Yuri Khan
  2021-11-16 12:00               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16 13:10               ` Emanuel Berg via Users list for the GNU Emacs text editor
  0 siblings, 2 replies; 55+ messages in thread
From: Yuri Khan @ 2021-11-16 11:52 UTC (permalink / raw)
  To: Emanuel Berg, help-gnu-emacs

On Tue, 16 Nov 2021 at 18:37, Emanuel Berg via Users list for the GNU
Emacs text editor <help-gnu-emacs@gnu.org> wrote:

> > Depending on circumstances, you might want to refine the
> > regexp to disallow leading zeros unless it is the only digit
> > in the integer part; and/or allow exponential format.

> As for disallowing leading zeroes I think it should be as
> close to Emacs as possible, eval 00 for example.

This is because I said “depending on circumstances”. You may want to
allow leading zeros and treat the number as decimal anyway, or you
might want to allow leading zeros and treat the number as octal, or
disallow leading zeros. It is application-specific.

> > It might also be a good idea to wrap all that in
> > a ‘save-match-data’.)
>
> What/how do you mean?

Suppose we put that function in a library and document it as “it
parses decimal numbers, checking that it is actually a decimal
number”.

A user tries to use the function between a (string-match …) and a
subsequent (match-beginning), (match-end), (match-string) or
(match-substitute-replacement). But our function itself uses
(string-match) so we trash the user’s match result.

(It is said somewhere that, generally, it is the caller’s
responsibility to preserve the match data across a function call that
might trash it, though. Maybe because this way yields better
performance when nobody actually cares about the last match data.)



^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16 11:52             ` Yuri Khan
@ 2021-11-16 12:00               ` Emanuel Berg via Users list for the GNU Emacs text editor
  2021-11-16 13:10               ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16 12:00 UTC (permalink / raw)
  To: help-gnu-emacs

Yuri Khan wrote:

>>> Depending on circumstances, you might want to refine the
>>> regexp to disallow leading zeros unless it is the only digit
>>> in the integer part; and/or allow exponential format.
>>
>> As for disallowing leading zeroes I think it should be as
>> close to Emacs as possible, eval 00 for example.
>
> This is because I said "depending on circumstances". You may
> want to allow leading zeros and treat the number as decimal
> anyway, or you might want to allow leading zeros and treat
> the number as octal, or disallow leading zeros. It is
> application-specific.
>
>>> It might also be a good idea to wrap all that in
>>> a ‘save-match-data’.)
>>
>> What/how do you mean?
>
> Suppose we put that function in a library and document it as
> "it parses decimal numbers, checking that it is actually
> a decimal number".
>
> A user tries to use the function between a (string-match ...)
> and a subsequent (match-beginning), (match-end),
> (match-string) or (match-substitute-replacement). But our
> function itself uses (string-match) so we trash the user’s
> match result.
>
> (It is said somewhere that, generally, it is the caller’s
> responsibility to preserve the match data across a function
> call that might trash it, though. Maybe because this way
> yields better performance when nobody actually cares about
> the last match data.)

OK ... nothing that clearly and instantly will improve
it, maybe.

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

* Re: How to read an integer from the minibuffer
  2021-11-16 11:52             ` Yuri Khan
  2021-11-16 12:00               ` Emanuel Berg via Users list for the GNU Emacs text editor
@ 2021-11-16 13:10               ` Emanuel Berg via Users list for the GNU Emacs text editor
  1 sibling, 0 replies; 55+ messages in thread
From: Emanuel Berg via Users list for the GNU Emacs text editor @ 2021-11-16 13:10 UTC (permalink / raw)
  To: help-gnu-emacs

Yuri Khan wrote:

>>> It might also be a good idea to wrap all that in
>>> a ‘save-match-data’.)
>>
>> What/how do you mean?
>
> Suppose we put that function in a library and document it as
> “it parses decimal numbers, checking that it is actually
> a decimal number”.
>
> A user tries to use the function between a (string-match …)
> and a subsequent (match-beginning), (match-end),
> (match-string) or (match-substitute-replacement). But our
> function itself uses (string-match) so we trash the user’s
> match result.

See `string-data-p':

  Same as ‘string-match’ except this function does not change
  the match data.

I also found this \\`syntax\\' - maybe that denotes the
beginning and end of the string, so one can use ^ and $ for
beginning-of-line and end-of-line only?

Both seem to work anyway ...

See the Java inspired unit testing last, well, maybe they got
it from us :P

(defun string-to-number-number (str)
  (let ((s (string-trim str)))
    (when (string-match-p
           "\\`[+-]?\\([[:digit:]]+\\|[[:digit:]]*\\.[[:digit:]]+\\)\\'" s)
      (string-to-number s) )))

(when nil
  (cl-map 'list (lambda (e)
                  (let ((a (car  e))
                        (b (cadr e)) )
                    (if (and a b)
                        (= a b)
                      (eq a b) )))
          (list
           (list (string-to-number-number " 10")                   10)
           (list (string-to-number-number "  1.5")                 1.5)
           (list (string-to-number-number " +0")                   0)
           (list (string-to-number-number "  0")                   0)
           (list (string-to-number-number " -0.0")                 -0.0)
           (list (string-to-number-number " -1.5")                -1.5)
           (list (string-to-number-number "-10")                  -10)
           (list (string-to-number-number "123this used to work")  nil)
           (list (string-to-number-number "NAN")                   nil)
           )) ; (t t t t t t t t t)
           ) 

-- 
underground experts united
https://dataswamp.org/~incal




^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2021-11-16 13:10 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-11-11  4:53 How to read an integer from the minibuffer Marcin Borkowski
2021-11-11  5:11 ` Po Lu
2021-11-11  7:18   ` Marcin Borkowski
2021-11-12  7:21     ` Yuri Khan
2021-11-13  6:59       ` Marcin Borkowski
2021-11-13  8:43         ` tomas
2021-11-13  7:33       ` Jean Louis
2021-11-16  6:39         ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16  7:37           ` Yuri Khan
2021-11-16  8:00             ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-11  6:27 ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-11 10:25 ` Gregory Heytings
2021-11-11 10:28   ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-11 11:00     ` Gregory Heytings
2021-11-11 13:20       ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-11 11:17 ` Gregory Heytings
2021-11-11 13:39   ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-11 14:30     ` Gregory Heytings
2021-11-12  0:28       ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12  0:37         ` Gregory Heytings
2021-11-12  0:41           ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12  0:52             ` Gregory Heytings
2021-11-12  0:57               ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12 19:05                 ` Jean Louis
2021-11-12 19:25                   ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12 19:55                     ` Jean Louis
2021-11-12 21:14                       ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-13  6:37                         ` Jean Louis
2021-11-16  6:21                           ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12 19:56                     ` Jean Louis
2021-11-12 20:02                     ` Jean Louis
2021-11-12 20:24                       ` tomas
2021-11-12 21:15                         ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12 21:30                           ` tomas
2021-11-12 21:34                             ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-13  6:46                           ` Jean Louis
2021-11-13  7:32                             ` tomas
2021-11-16  6:24                             ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-13  6:36                         ` Jean Louis
2021-11-13  8:17                           ` tomas
2021-11-13  8:44                             ` Jean Louis
2021-11-16  6:15                               ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16  6:03                             ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12  1:09               ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12  1:12                 ` Gregory Heytings
2021-11-12  3:07                   ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-12  6:21 ` Marcin Borkowski
2021-11-16  7:52   ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16  8:05     ` Yuri Khan
2021-11-16  9:38       ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16 11:18         ` Yuri Khan
2021-11-16 11:37           ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16 11:52             ` Yuri Khan
2021-11-16 12:00               ` Emanuel Berg via Users list for the GNU Emacs text editor
2021-11-16 13:10               ` Emanuel Berg via Users list for the GNU Emacs text editor

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.