Jonathan Handojo Posted November 18, 2019 Posted November 18, 2019 (edited) Hi all, This might be a silly question coming from someone who has quite a bit of experience with AutoLISP, but what's the best way to retrieve the consecutive integers at the end of a string? For example, consider the texts "Test123", or "ComputerNumber_55", or "Puzzle #50-23". How can I extract just "123" from "Test123", "55" from "ComputerNumber_55", and "23" from Puzzle #50-23". (They're only integers, no real numbers like [for instance], "Version 1.2" or "Give me $5.00") I can create a function with like 30 lines or so, but I feel it's wrong and might slow my CAD down considering hundreds of data. Any help is appreciated. Thanks, Jonathan Handojo Edited November 18, 2019 by Jonathan Handojo Quote
Tharwat Posted November 18, 2019 Posted November 18, 2019 (edited) Here is my attempt. (defun end:digits ( str / new rtn ) (and (wcmatch str "*#") (setq new "" str (vl-list->string (reverse (vl-string->list str)))) (while (and (setq rtn (substr str 1 1)) (/= rtn ".") (numberp (read rtn)) (setq new (strcat rtn new) str (substr str 2) ) ) ) ) (if (/= new "") new) ) (vl-load-com) Edited November 19, 2019 by Tharwat Quote
dlanorh Posted November 18, 2019 Posted November 18, 2019 My attempt. Returns a string if you want an integer returned uncomment the last line and remove the one above (defun last_int ( str / n) (vl-every '(lambda (x) (if (< 47 x 58) (setq n (cons x n)))) (reverse (vl-string->list str))) (apply 'strcat (mapcar 'chr n)) ;(atoi (apply 'strcat (mapcar 'chr n))) );end_defun Quote
Jonathan Handojo Posted November 18, 2019 Author Posted November 18, 2019 (edited) Ahhh... Of course, how could I've missed vl-string->list. That makes things so much easier. Thanks Tharwat and dlanorh, they both works just fine! With that, I would've just then used vl-some and stop on the first non-numeric character. Again, thanks for the functions both! Thanks, Jonathan Handojo Edited November 18, 2019 by Jonathan Handojo Quote
Tharwat Posted November 18, 2019 Posted November 18, 2019 (edited) You're welcome anytime. Another without the use of the vl functions. (defun end:digits (str / new itm) (and (wcmatch str "*#") (while (and str (/= str "")) (setq new (cons (substr str 1 1) new) str (substr str 2) ) ) (while (and new (setq itm (car new)) (/= itm ".") (numberp (read itm))) (setq str (strcat itm str) new (cdr new) ) ) ) (if new str) ) Edited November 19, 2019 by Tharwat Decimal dot avoided. Quote
Jonathan Handojo Posted November 18, 2019 Author Posted November 18, 2019 Well, whatever simplest and fastest works best. I suppose the more number of parenthesis, the slower it is. In the end, I combined your use of numberp and read, and dlanorh's idea of vl-every to get: (defun last_int (str / final) (vl-some '(lambda (x) (if (numberp (read x)) (progn (setq final (cons x final)) nil) (apply 'strcat final) ) ) (reverse (mapcar 'chr (vl-string->list str))) ) ) Thanks, Jonathan Handojo Quote
ronjonp Posted November 18, 2019 Posted November 18, 2019 (edited) 2 hours ago, Jonathan Handojo said: Well, whatever simplest and fastest works best. I suppose the more number of parenthesis, the slower it is. In the end, I combined your use of numberp and read, and dlanorh's idea of vl-every to get: (defun last_int (str / final) (vl-some '(lambda (x) (if (numberp (read x)) (progn (setq final (cons x final)) nil) (apply 'strcat final) ) ) (reverse (mapcar 'chr (vl-string->list str))) ) ) Thanks, Jonathan Handojo I know you said there aren't any reals but (wcmatch x "#") would be a safer check in my opinion: Try: (read ".") Edited November 18, 2019 by ronjonp 1 Quote
Jonathan Handojo Posted November 18, 2019 Author Posted November 18, 2019 (edited) Ahh, I see. (read ".") yields an error, so texts like "Puzzle v12.00" won't work. Thanks for that ronjonp. Looks like I still have miles to learn about this. Edited November 18, 2019 by Jonathan Handojo Quote
ronjonp Posted November 18, 2019 Posted November 18, 2019 27 minutes ago, Jonathan Handojo said: Looks like I still have miles to learn about this. So do I Quote
Grrr Posted November 18, 2019 Posted November 18, 2019 Two more: (defun LastInt (s / i q r) (if (/= "" s) (while (and (> (setq i (strlen s)) 0) (wcmatch (setq q (substr s i 1)) "#")) (setq r (cons q r)) (setq s (substr s 1 (1- i))) ) ) (if r (atoi (apply 'strcat r))) ) (defun LastInt (s / r) (setq r "") (vl-catch-all-apply (function (lambda nil (foreach x (reverse (vl-string->list s)) (or (and (<= 48 x 57) (setq r (strcat (chr x) r))) (exit) ) ) ) ) ) (if (/= "" r) (atoi r)) ) Quote
BIGAL Posted November 19, 2019 Posted November 19, 2019 (edited) Sorry guys Hail the king, only 5 years to late ;; Parse Numbers - Lee Mac ;; Parses a list of numerical values from a supplied string. ;; Author: Lee Mac, Copyright © 2013 - www.lee-mac.com ;; : (lm:parsenumbers "Puzzle #50-23") (50 23) : (lm:parsenumbers "Test123") (123) : (lm:parsenumbers "ComputerNumber_55") (55) : (lm:parsenumbers "Puzzle v12.00") (12.0) Credit also Tharwat for the MAC would be a solution. Edited November 19, 2019 by BIGAL Quote
Tharwat Posted November 19, 2019 Posted November 19, 2019 I was talking to myself a few minutes a go, how come bigal did not stamp his finger in this thread also yet? Quote
Jonathan Handojo Posted November 19, 2019 Author Posted November 19, 2019 Oh lord... Good to know, but; 11 minutes ago, BIGAL said: (lm:parsenumbers "Puzzle v12.00") (12.0) I'd actually want this to result in "00" instead. I'd literally only want the last integers in the string, be it any other symbol than numbers from the end. Otherwise yea... that would've been (last (lm:parsenumbers "Puzzle #50-23")) You certainly got me there mate! Haha. Thanks, Jonathan Handojo Quote
Lee Mac Posted November 19, 2019 Posted November 19, 2019 (edited) Here's another, recursive variation: (defun lastint ( s ) (if (wcmatch s "*#") (strcat (lastint (substr s 1 (1- (strlen s)))) (substr s (strlen s))) "" ) ) @Jonathan Handojo Fewer parentheses doesn't necessarily equate to greater efficiency: for example, the above recursive solution will likely be slower than the other iterative solutions posted in this thread... Edited November 19, 2019 by Lee Mac Quote
Jonathan Handojo Posted November 19, 2019 Author Posted November 19, 2019 (edited) Quote Sorry guys Hail the king, only 5 years to late Lol, the king actually showed up 41 minutes ago, Lee Mac said: Here's another, recursive variation: (defun lastint ( s ) (if (wcmatch s "*#") (strcat (lastint (substr s 1 (1- (strlen s)))) (substr s (strlen s))) "" ) ) @Jonathan Handojo Fewer parentheses doesn't necessarily equate to greater efficiency: for example, the above recursive solution will likely be slower than the other iterative solutions posted in this thread... Makes sense though. Definitely much shorter than all the solutions in this thread to date (in terms of length), but if the text is really long, the function will have to keep being called more times. I totally forgot about recursive functions, and to be honest I'm quite weak at it in using it than iterative methods. I've been trying to use it and create other simple functions. For example: The below will return a list of points between p1 and p2 at a specified interval, with a given option for some threshold at the last segment. I had to go through all sorts of hell to finally get it working. I still need to develop my "recursive" thinking better. (defun pt_intervals (p1 p2 len threshold) ; Returns a list points between p1 and p2 at intervals of 'len' with a given 'threshold' at the last segment. (cond ; It simply means that the last segment should have a minimum length of the given 'threshold' ((< (distance p1 p2) (+ len threshold)) (list p2)) ((>= (distance p1 p2) len) (cons (polar p1 (angle p1 p2) len) (pt_intervals (polar p1 (angle p1 p2) len) p2 len threshold))) ) ) Thanks, Jonathan Handojo Edited November 19, 2019 by Jonathan Handojo Quote
Lee Mac Posted November 19, 2019 Posted November 19, 2019 Recursive functions have their place and, if mastered, are another useful tool in your toolbox, but ultimately it is about selecting the appropriate tool for the job: writing everything recursively may yield elegant and concise code, but ultimately you'll pay in performance and memory overhead; then again, other tasks (such as traversing nested structures) are ill-suited to iterative methods whereas recursion can tackle them with ease. FWIW, you needn't test the distance twice, and hence your cond statement could be reduced to an if, e.g.: (defun pt_intervals ( p q l f ) (if (<= (+ l f) (distance p q)) (cons (polar p (angle p q) l) (pt_intervals (polar p (angle p q) l) q l f)) (list q) ) ) Quote
Grrr Posted November 19, 2019 Posted November 19, 2019 1 hour ago, Jonathan Handojo said: I totally forgot about recursive functions, and to be honest I'm quite weak at it in using it than iterative methods. Wheres iteration theres also a linear recursion and vice-versa. BTW during my participation in the LISP forums Lee's proven to be the master of recursions (and not just them but also of different insane list manipulations). Quote
BIGAL Posted November 20, 2019 Posted November 20, 2019 Johnathon there is some lisp for pad zeros out there prefix or suffix. D1 no D01 V12.0000 how many after . 12.0 12.00 12.000 Quote
Jonathan Handojo Posted November 20, 2019 Author Posted November 20, 2019 10 hours ago, BIGAL said: Johnathon there is some lisp for pad zeros out there prefix or suffix. D1 no D01 V12.0000 how many after . 12.0 12.00 12.000 If you mean in terms of string, I think that's easy to implement. But if it's in the form of a real number, I don't know how to get that. Even Lee Mac's round (LM;:roundto 1.2 4) returns only 1.2, not 1.2000. Quote
BIGAL Posted November 21, 2019 Posted November 21, 2019 (edited) 1.2 = 1.20 = 1.200 = 1.20000 no matter how many decimal places. Yes may need to be string just a fact of life, there is some #.## funtions but never used them. Edited November 21, 2019 by BIGAL Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.