* 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 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 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 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: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-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 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-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-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 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 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 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: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: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: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 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-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-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 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 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-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-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-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-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 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: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 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-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-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: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
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).