Jump to content

Issue with replacing real numbers in text strings with sums in AutoLISP


PabloS

Recommended Posts

Hello everyone:

 

I'm currently working on an AutoLISP routine where I'm trying to replace each real number (with 2 or 3 decimal places) within text strings in AutoCAD drawings with the sum of each number plus a value input by the user.

 

I've written a function to accomplish this task, but it seems that the regular expression I'm using isn't capturing the numbers correctly. Despite the text strings containing numbers like 4.52, 3.142, or 5.500, the replacement isn't happening.

 

Here's the code snippet I'm using for the replacement function:

(defun reemplazarNumeros (texto num)
  (setq nuevoTexto "")
  (setq regex "[-+]?[0-9]*\\.?[0-9]+")
  (setq inicio 1)
  (setq fin (strlen texto))

  (while (<= inicio fin)
    (setq match (vl-string-search regex texto inicio))
    (if match
      (progn
        (setq numero (substr texto (match 1) (match 0)))
        (setq numero (atof numero))
        (setq nuevoNumero (+ numero num))
        (setq nuevoNumeroStr (rtos nuevoNumero 2 2))
        (setq nuevoTexto (strcat nuevoTexto (substr texto inicio (match 1)) nuevoNumeroStr))
        (setq inicio (match 0))
      )
      (progn
        (setq nuevoTexto (strcat nuevoTexto (substr texto inicio)))
        (setq inicio (1+ fin))
      )
    )
  )
  nuevoTexto
)

 

I would appreciate any insights or suggestions on why the replacement isn't working as expected and how I could fix it. Thank you in advance for your help!

Link to comment
Share on other sites

Posted (edited)

vl-string-search (or more accurately, vl-string-subst) isn't used to capture Regular Expression. It's meant to capture exact matches.

 

I recommend using this function from Lee Mac: Parse Numbers

 

After which, you can use this:

 

(setq tst "12.43 93.32 hrui23 -43")
(apply '+ (LM:parsenumbers tst))

 

However, if you must use regular expression, I have a small function that accomplishes this (although mine is widely case-insensitive):

 

(defun JH:RegEx-Find (str pat / i j mch rtn s sub)
    (vlax-put-property (JH:Regex_Object) "Pattern" pat)
    (setq mch (vl-catch-all-apply 'vlax-invoke (list (JH:Regex_Object) "Execute" str)))
    (if (not (vl-catch-all-error-p mch))
        (progn
            (vlax-for m mch
                (setq sub nil s (vlax-get-property m "SubMatches"))
                (repeat (setq i (vla-get-count s) j i)
                    (setq sub (cons (vlax-variant-value (vlax-get-property s "Item" (- j i))) sub) i (1- i))
                )
                (setq rtn (cons (list (vla-get-value m) (reverse sub)) rtn))
            )
            (reverse rtn)
        )
    )
)

(defun JH:Regex_Object ( / rx)
    (setq rx (vlax-get-or-create-object "VBScript.RegExp"))
    (vlax-put-property rx "Global" :vlax-true)
    (vlax-put-property rx "Multiline" :vlax-true)
    (vlax-put-property rx "IgnoreCase" :vlax-false)
    (eval
        (list 'defun 'JH:Regex_Object '()
            rx
        )
    )
    (JH:Regex_Object)
)

 

After which, you can call it like this:

 

(setq tst "12.43 93.32 hrui23 -43")
(apply '+ 
    (mapcar 'distof 
        (mapcar 'car 
            (JH:Regex-Find tst
                "[-\\+]?\\d+(\\.\\d+)?"
            )
        )
    )
)

 

Edited by Jonathan Handojo
  • Like 1
Link to comment
Share on other sites

@Jonathan Handojo, thanks for your time to answer.

 

I managed to change numbers but still have one problem: Preserving Non-Numeric Parts of Text

 

The current implementation updates the numerical values correctly, but it doesn't preserve the non-numeric parts of the text. For example, if I have a text entity like "NPT 5.200" and I input "3.12", the text is changed to "8.3200" instead of "NPT 8.320". I need to find a way to preserve the non-numeric parts of the text while updating only the numerical values.

 

Here is the code:

(defun c:modificarTexto (/ numSeleccionado textosSeleccionados)
  (setq numSeleccionado (getreal "\nIngrese un número real de 2 decimales: "))

  (if (not (zerop numSeleccionado))
    (progn
      (setq textosSeleccionados (ssget '((0 . "TEXT"))))

      (if textosSeleccionados
        (progn
          (setq contador 0)
          (while (< contador (sslength textosSeleccionados))
            (setq entidad (ssname textosSeleccionados contador))
            (setq texto (cdr (assoc 1 (entget entidad))))
            
            ; Parse the numbers from the text using Lee Mac's function
            (setq numeros (LM:parsenumbers texto))
            
            ; Update each number by adding the user input
            (setq nuevosNumeros (mapcar '(lambda (x) (+ x numSeleccionado)) numeros))
            
            ; Construct the new text with updated numbers
            (setq nuevoTexto (apply 'strcat (mapcar 'rtos nuevosNumeros)))
            
            ; Update the text entity in the drawing
            (entmod (subst (cons 1 nuevoTexto) (assoc 1 (entget entidad)) (entget entidad)))

            (setq contador (1+ contador))
          )
          (princ "\nTodos los números han sido actualizados.")
        )
        (princ "\nNo se han encontrado textos para actualizar.")
      )
    )
    (princ "\nEl número ingresado no es válido.")
  )
  (princ)
)

(defun LM:parsenumbers ( str )
    (   (lambda ( l )
            (read
                (strcat "("
                    (vl-list->string
                        (mapcar
                           '(lambda ( a b c )
                                (if (or (< 47 b 58)
                                        (and (= 45 b) (< 47 c 58) (not (< 47 a 58)))
                                        (and (= 46 b) (< 47 a 58) (< 47 c 58))
                                    )
                                    b 32
                                )
                            )
                            (cons nil l) l (append (cdr l) '(()))
                        )
                    )
                    ")"
                )
            )
        )
        (vl-string->list str)
    )
)

 

Any Idea?

 

Regards,

Pablo

Link to comment
Share on other sites

Posted (edited)

Oh, my general understanding of your query is wrong... I thought you wanted to add ALL the values from the parsed number...

 

2 hours ago, PabloS said:

with the sum of each number

 

In such cases, you will need to look at using vl-string-subst instead. My approach would be to void using LM:parsenumbers and go with using Regular Expression (to account for any leading/trailing zeros). And for each regular expression match you find, you use vl-string-subst each time. Someone may have a more efficient approach than mine.

 

...this is why I don't like dealing with real numbers and strings

Edited by Jonathan Handojo
Link to comment
Share on other sites

My try:

(defun pp(txt toadd)
  (setq i 0 p1 nil p2 nil)
  (repeat (strlen txt)
    (setq char (substr txt (setq i (1+ i)) 1))
    (setq c (and (> (ascii char) (ascii "0")) (< (ascii char) (ascii "9"))))
    (setq p1 (if (and (not p1) c) i p1))
    (setq p2 (if (and p1 c) i p2))
    )
  (setq sum (rtos (+ toadd (read (substr txt p1 (- p2 p1 -1))))) l (strlen sum))
  (cond ((vl-string-search "." sum) (while (= "0" (substr sum l 1)) (setq l (1- l) sum (substr sum 1 l)))))
  (setq sum (if (= "." (substr sum l 1)) (substr sum 1 (1- l)) sum))
  (strcat (substr txt 1 (1- p1)) sum (substr txt (1+ p2)))
  )

 

Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...