Jump to content

Basic lisp help with str manipulation


Organic

Recommended Posts

Below is a lisp from gjrcmb on the Autodesk forums (http://forums.autodesk.com/t5/autocad-2010-2011-2012/replacing-part-of-a-text-string/m-p/3390397#M14465)

 

The lisp removes characters from the end of text strings.

 

Below is my attempt at doing this (from someone who does not know lisp). I understand that

(substr otxt 2 (- (strlen otxt) 0)

looks at the string otxt and will start the new string from the second character (i.e. remove the first character) and then continue on for the length of the string.

 

I want to remove two characters and regardless of what nchar is, my hacked version of the lisp only removes the first character of the string. This is not a big deal as I can simply run the lisp twice to get the result I want although wondered how/what is required to correctly make the lisp work for more than one character at the start at a time?

 

Original lisp:

;;Application to remove specifed number of characters from the end of Text and MText objects
(defun c:RemCharHack (/ adoc sstxt nchar n elst otxt ntxt nlst)
   (vl-load-com)
   (setq adoc (vla-get-activedocument (vlax-get-acad-object)))
   (princ "Select Text Objects to Remove Characters From.")
   (setq sstxt (ssget '((-4 . "<OR") (0 . "TEXT") (0 . "MTEXT") (-4 . "OR>"))))
   (while (null (setq nchar (getint "\nSpecify Number of Characters to Remove from End of Text Objects: ")))
       (princ "**Invalid Entry**")
   )
   (setq n 0)
   (vla-StartUndoMark adoc)
   (repeat (sslength sstxt)
       (setq elst (entget (ssname sstxt n)))
       (setq otxt (cdr (assoc 1 elst)))
       (if (> (strlen otxt) nchar)
           (progn
               (setq ntxt (substr otxt 1 (- (strlen otxt) nchar)))
               (setq nlst (subst (cons 1 ntxt) (assoc 1 elst) elst))
               (entmod nlst)
           )
           (progn
               (princ (strcat "\nExisting Text Object \"" otxt "\" Has Too Few Characters.")) 
               (princ (strcat "\nText Object \"" otxt "\" Not Modified!!\n"))
           )
       )
       (setq n (1+ n))
   )
   (vla-EndUndoMark adoc)
   (princ)
)

I would like to modify the lisp to remove characters from the start of the string instead.

 

My attempt:

;;Application to remove specifed number of characters from the end of Text and MText objects
(defun c:RemChar4 (/ adoc sstxt nchar n elst otxt ntxt nlst)
   (vl-load-com)
   (setq adoc (vla-get-activedocument (vlax-get-acad-object)))
   (princ "Select Text Objects to Remove Characters From.")
   (setq sstxt (ssget '((-4 . "<OR") (0 . "TEXT") (0 . "MTEXT") (-4 . "OR>"))))
   (while (null (setq nchar (getint "\nSpecify Number of Characters to Remove from Start of Text Objects: ")))
       (princ "**Invalid Entry**")
   )
   
   (setq n 0)
   ;;(vla-StartUndoMark adoc)
   (repeat (sslength sstxt)
       (setq elst (entget (ssname sstxt n)))
       (setq otxt (cdr (assoc 1 elst)))
       (if (> (strlen otxt) nchar)
           (progn
               (setq ntxt (substr otxt 2 (- (strlen otxt) 0)))
               (setq nlst (subst (cons 1 ntxt) (assoc 1 elst) elst))
               (entmod nlst)
           )
           (progn
               (princ (strcat "\nExisting Text Object \"" otxt "\" Has Too Few Characters.")) 
               (princ (strcat "\nText Object \"" otxt "\" Not Modified!!\n"))
           )
       )
       (setq n (1+ n))
   )
   ;;(vla-EndUndoMark adoc)
   (princ)
)

Cheers

Link to comment
Share on other sites

Since the substr function uses a one-based index to address the characters in a string (that is, the first character is at index 1; as opposed to the zero-based index used by most other functions), in order to remove two characters, you would need to return all characters from the character at index 3 onward (hence removing characters 1 & 2):

 

_$ (substr "abc123" 3)
"c123"

 

Consider the following code:

(defun c:rem2char ( / enx idx sel str )
   (if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
       (repeat (setq idx (sslength sel))
           (setq enx (entget (ssname sel (setq idx (1- idx))))
                 str (cdr (assoc 1 enx))
           )
           (if (< 2 (strlen str))
               (entmod (subst (cons 1 (substr str 3)) (assoc 1 enx) enx))
               (princ (strcat "\nExisting text object \"" str "\" has too few characters."))
           )
       )
   )
   (princ)
)

Link to comment
Share on other sites

Thanks Lee, that makes sense. Your lisp is exactly what I was trying (for a good hour plus) to achieve :D

 

You're welcome Organic, I'm glad that my explanation was clear -

If you have any other questions about the posted code, feel free to ask.

 

Lee

Link to comment
Share on other sites

If I have a string such as "THE RED CAT" and wanted to modify it to "THE CAT" would you just break it down into two substrs or "THE " and "CAT" and then concatenate them together? Or is there a better way of doing it? E.g. keep characters 1 to 4 and 9 to 11, but remove characters 5 to 8.

Link to comment
Share on other sites

If I have a string such as "THE RED CAT" and wanted to modify it to "THE CAT" would you just break it down into two substrs or "THE " and "CAT" and then concatenate them together?

 

That is how I would approach it, yes.

 

An alternative could be to use vl-string-subst in the following way:

_$ (vl-string-subst "" " RED" "THE RED CAT")
"THE CAT"

Link to comment
Share on other sites

Hello Lee

 

Is there a way of modifying the lisp to prompt: 'Characters to be removed' to specify by how much the string is to be shortened?

Link to comment
Share on other sites

Is there a way of modifying the lisp to prompt: 'Characters to be removed' to specify by how much the string is to be shortened?

 

Certainly - consider the following:

(defun c:remchars ( / enx idx num sel str )
   (initget 6)
   (if (and (setq num (getint "\nNumber of characters to remove: ")) 
            (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
       )
       (repeat (setq idx (sslength sel))
           (setq enx (entget (ssname sel (setq idx (1- idx))))
                 str (cdr (assoc 1 enx))
           )
           (if (< num (strlen str))
               (entmod (subst (cons 1 (substr str (1+ num))) (assoc 1 enx) enx))
               (princ (strcat "\nExisting text object \"" str "\" has too few characters."))
           )
       )
   )
   (princ)
)

Link to comment
Share on other sites

That's bizarre.

It loaded with no problem or warnings

I tried it on a MTEXT entity & it resulted in a prefix added which says: "fArial|b0|i0|c238|p34;" without quotes.

It seems to work fine on TEXT entities though

Am I doing anything wrong?

Link to comment
Share on other sites

That's bizarre.

It loaded with no problem or warnings

I tried it on a MTEXT entity & it resulted in a prefix added which says: "fArial|b0|i0|c238|p34;" without quotes.

It seems to work fine on TEXT entities though

Am I doing anything wrong?

 

This is because your MText contains formatting codes within the text content (you can view these codes in the text content shown in the Properties Palette) - such formatting codes arise when formatting overrides are applied through the MText Editor.

 

The presence of MText formatting renders this otherwise simple task significantly more difficult as the program must first separate the formatting codes from the displayed text content, before modifying the displayed content, and reinserting the formatting codes. However, what if the formatting was only applied to the first or second characters which are now removed? The program would need to account for such cases and remove any formatting codes surrounding only these characters...

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...