Delete numbers from text

Delete numbers from text

johnbogaert5351
Participant Participant
3,902 Views
12 Replies
Message 1 of 13

Delete numbers from text

johnbogaert5351
Participant
Participant

Hi all,

 

I have a question about removing decimal numbers from mtext or dtext.

I have mtext and dtext in a lot of drawings containing numbers in the text.

For example; Office 0578 or Corridor 778069 and so on.

I am not familiar with Lisp but is there a Lisp routine which removes  the numbers from the text with a lisp routine.

So the text will be Office and Corridor.

 

I hope someone can help me.

 

John

0 Likes
Accepted solutions (1)
3,903 Views
12 Replies
Replies (12)
Message 2 of 13

Kent1Cooper
Consultant
Consultant

If the number parts are always at the end, it would be built on something like this:

 

(VL-STRING-RIGHT-TRIM " 0123456789" "THIS IS A TEST 13265")

 

returns


"THIS IS A TEST"

 

I may come up with a routine later, if someone else doesn't beat me to it.

 

[There's no such entity type as DTEXT, by the way -- it's just TEXT.]

Kent Cooper, AIA
0 Likes
Message 3 of 13

johnbogaert5351
Participant
Participant

Hi Kent,

 

the numbers are not always at the end.

The position of the numbers is random. Begin, middle and at the end of the text.

 

I hope someone can make a simple Lisp routine.

That will be very helpful.

 

John

0 Likes
Message 4 of 13

john.uhden
Mentor
Mentor

That's gonna be a tough one with Mtext that may contain formatting for obliquing and width factors.

John F. Uhden

0 Likes
Message 5 of 13

DannyNL
Advisor
Advisor

As John said MText with formatting will be complicating things, but for normal text and non-formatted MText, this might do the trick and give you a start. But do not use on formatted MText as that will most likely give strange and unpredicted results.
As removing numbers in text will give you unwanted spaces, spaces on the left and right are removed plus double spaces within the text will be replaced by a single space.

 

(defun c:RemoveNumbers (/ RN_Object)
   (if
      (and
         (setq RN_Object (car (entsel "\nSelect text: ")))
         (or
            (= (vla-get-ObjectName (setq RN_Object (vlax-ename->vla-object RN_Object))) "AcDbText")
            (= (vla-get-ObjectName                                         RN_Object)   "AcDbMText")
         )
      )
      (progn
         (if
            (RegEx "\\d+" (setq RN_Text (vla-get-TextString RN_Object)))
            (vla-put-TextString RN_Object (StripNumbers RN_Text))
            (princ "\n ** No numbers detected in text")
         )
      )
      (princ "\n ** Nothing or no text selected")
   )
   (princ)
)

(defun RegEx (RE_Pattern RE_SearchString / RE_RegExObject RE_Result RE_Return)
   (if
      (and
         (= (type RE_SearchString) 'STR)
         (= (type RE_Pattern)      'STR)
      )
      (progn
         (setq RE_RegExObject (vlax-get-or-create-object "VBScript.RegExp"))
         (vlax-put-property RE_RegExObject 'Pattern RE_Pattern)
         (setq RE_Result (vl-catch-all-apply 'vlax-invoke-method (list RE_RegExObject 'Execute RE_SearchString)))
         (if
            (and
               (not (vl-catch-all-error-p RE_Result))
               (> (vla-get-Count RE_Result) 0)
            )      
            (setq RE_Return (vla-get-Value (vlax-get-property RE_Result 'Item 0)))      
         )
         (vlax-release-object RE_RegExObject)
      )
   )
   RE_Return
)

(defun StripNumbers (SN_Text / SN_NumberFound)
   (while
      (setq SN_NumberFound (RegEx "\\d+" SN_Text))
      (setq SN_Text (vl-string-trim " " (vl-string-subst "" SN_NumberFound SN_Text)))
   )
   (while
      (vl-string-search "  " SN_Text)
      (setq SN_Text (vl-string-subst " " "  " SN_Text))
   )
   SN_Text
)

 

0 Likes
Message 6 of 13

johnbogaert5351
Participant
Participant

Wow, thanks DaBrassi.

This works pretty well.

 

But,..... Can I also select more than one object....... or all??

 

Thanks in advance.

 

John

0 Likes
Message 7 of 13

stevor
Collaborator
Collaborator

From that, your numbers are sequences of integer characters, only?

Or, can it contain a '-' or a '.' ?

S
0 Likes
Message 8 of 13

johnbogaert5351
Participant
Participant

Hi Stevor,

 

Yes, the numbers are always sequences of integer characters.

 

John

0 Likes
Message 9 of 13

Kent1Cooper
Consultant
Consultant

If your Mtext doesn't contain formatting codes involving numbers for things like color/width factor/obliquing/height overrides, nor any stacked fractions, but all numerical characters are always and only the ones you want removed, then something as simple as this seems to work, in very limited testing [including multiple-object selection]:

 

(vl-load-com)
(defun C:SNT (/ txtent txt) ; = Strip Numbers from Text
  (prompt "\nTo Strip Numbers from Text,")
  (if (setq ss (ssget '((0 . "*TEXT") (1 . "*#*"))))
    (repeat (setq n (sslength ss))
      (setq
        txtent (ssname ss (setq n (1- n)))
        txt (cdr (assoc 1 (entget txtent)))
      ); setq
      (while (wcmatch txt "*#*"); still contains any numbers
        (foreach num '("0" "1" "2" "3" "4" "5" "6" "7" "8" "9")
          (setq txt (vl-string-subst "" num txt))
        ); foreach
      ); while
      (vla-put-TextString (vlax-ename->vla-object txtent) (vl-string-trim " " txt))
    ); repeat
  ); if
); defun

 

It also removes any leftover leading/trailing spaces, but not decimal points or hyphens or slashes of un-stacked fractions, foot or inch marks, etc.  And if a string consists of only numerical characters, it will become invisible -- I guess it could be adjusted to check whether the string is emptied completely, and if so, delete the object rather than change its contents to nothing.

Kent Cooper, AIA
Message 10 of 13

DannyNL
Advisor
Advisor

Hi John,

 

I've modified my code to enable to select multiple objects. Also what Kent mentioned when a text only contains numbers, will be checked for. In this case a text with only numbers will not be processed, but the code can easily be modified to delete those objects if necessary.

As with selecting multiple texts it's also more likely that something can go wrong, I've added the option to undo all changes with one UNDO command.

 

Code can be optimized a bit more, but I have to do this in between other stuff so just made some quick changes Smiley Happy

 

BTW, sorry I replied to wrong and your post Kent instead of John's.

 

(defun c:RemoveNumbers (/ RN_Selection RN_Count RN_Object RN_NewString)
   (setq RN_Selection (ssget '((0 . "*TEXT"))))
   (if
      RN_Selection
      (progn
         (setq RN_Count 0)
         (vla-StartUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
         (while
            (setq RN_Object (ssname RN_Selection RN_Count))             
            (progn
               (if
                  (RegEx "\\d+" (setq RN_Text (vla-get-TextString (setq RN_Object (vlax-ename->vla-object RN_Object)))))
                  (if
                     (/= (setq RN_NewString (StripNumbers RN_Text)) "")
                     (vla-put-TextString RN_Object RN_NewString)
                  )
               )
            )
            (setq RN_Count (1+ RN_Count))
         )
         (vla-EndUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
      )
      (princ "\n ** Nothing or no texts selected")
   )
   (princ)
)

(defun RegEx (RE_Pattern RE_SearchString / RE_RegExObject RE_Result RE_Return)
   (if
      (and
         (= (type RE_SearchString) 'STR)
         (= (type RE_Pattern)      'STR)
      )
      (progn
         (setq RE_RegExObject (vlax-get-or-create-object "VBScript.RegExp"))
         (vlax-put-property RE_RegExObject 'Pattern RE_Pattern)
         (setq RE_Result (vl-catch-all-apply 'vlax-invoke-method (list RE_RegExObject 'Execute RE_SearchString)))
         (if
            (and
               (not (vl-catch-all-error-p RE_Result))
               (> (vla-get-Count RE_Result) 0)
            )      
            (setq RE_Return (vla-get-Value (vlax-get-property RE_Result 'Item 0)))      
         )
         (vlax-release-object RE_RegExObject)
      )
   )
   RE_Return
)

(defun StripNumbers (SN_Text / SN_NumberFound)
   (while
      (setq SN_NumberFound (RegEx "\\d+" SN_Text))
      (setq SN_Text (vl-string-trim " " (vl-string-subst "" SN_NumberFound SN_Text)))
   )
   (while
      (vl-string-search "  " SN_Text)
      (setq SN_Text (vl-string-subst " " "  " SN_Text))
   )
   SN_Text
)

 

Message 11 of 13

johnbogaert5351
Participant
Participant

Thanks a lot for the quick and fast reactions.

 

These routine's are very useful for me. Thumbs up!

 

John

 

0 Likes
Message 12 of 13

joselggalan
Advocate
Advocate

 

Another option:

 

(defun Remove_sNum (s / lstsNum)
 (setq lstsNum (vl-string->list "0123456789"))
 (vl-list->string
  (vl-remove-if
   (function
    (lambda (n)
     (vl-position n lstsNum)
    )
   )
   (vl-string->list s)
  )
 )
)

Test:

$ (Remove_sNum "00This12 is344 a567 test89999")
"This is a test"
Message 13 of 13

Kent1Cooper
Consultant
Consultant
Accepted solution

@Kent1Cooper wrote:

If your Mtext doesn't contain formatting codes involving numbers ..., nor any stacked fractions, but all numerical characters are always and only the ones you want removed, then something as simple as this ....

 

It also removes any leftover leading/trailing spaces, but not decimal points or hyphens or slashes of un-stacked fractions, foot or inch marks, etc.  ....


And yet another way [with the same limitations as above], using a different approach involving the ASCII character codes that @joselggalan has brought up:

 

(vl-load-com)
(defun C:SNT (/ txtent txt) ; = Strip Numbers from Text
  (prompt "\nTo Strip Numbers from Text,")
  (if (setq ss (ssget '((0 . "*TEXT") (1 . "*#*"))))
    (repeat (setq n (sslength ss))
      (vla-put-TextString
        (setq txtobj (vlax-ename->vla-object (ssname ss (setq n (1- n)))))
        (vl-string-trim " "
          (vl-list->string
            (vl-remove-if '(lambda (x) (< 47 x 58)); dump if from 0 [48] to 9 [57]
              (vl-string->list (vla-get-TextString txtobj)); as character codes
            ); ...remove...
          ); ...list...
        ); ...put...
      ); ...trim...
    ); repeat
  ); if
); defun

This should be faster than my previous routine, since this takes all of them out at once, whereas (vl-string-subst) replaces only the first instance of what it's aiming to replace, so it has to keep looking again, and since the earlier routine runs a substitution for every  numerical character, even when not all are present.

 

Kent Cooper, AIA
0 Likes