Author Topic: [Solved] Text translator  (Read 6382 times)

0 Members and 1 Guest are viewing this topic.

zibidi

  • Guest
[Solved] Text translator
« on: July 18, 2007, 12:18:52 PM »
EDIT: The base code is complete and works, here are new features that could be added on top and that would be awesome to have:
- regexp text appended to dimensions
- update text in annotations
- update text inside blocks

------------------------------------------------------------------------------------------------

Completed base code:
Code: [Select]
(defun C:PT (/ )

;newlines are marked as \P in autocad text.

(setq path2file (findfile "ProTranslator.dat")) ;path to the data file

(setq listOfText (ssget "_X" '((0 . "*TEXT")))) ;fetch all the text entities on the drawing

;(alert (itoa (sslength listofText)))
;To display a number in alert box, you have to first make it into a string.

(setq pointer 0);that's the pointer inside the listOfText. Lists begin with an index of 0

(repeat (setq n (sslength listOfText))
;count how many text entities have been found, and loop n times
;because of the way we move in our list, we need to redefine n each time we loop

(setq fileData (open path2file "r")) ;open the data file and assign it to fileData

(setq textEntity (entget (ssname listOfText pointer)))
;retrieve the text entity so that we can modify its text attribute using entmod

(setq textEntityContent (strcase (cdr (assoc 1 textEntity))));select the text content from the
;text entity
;strcase converts the string into HIGHCAPS so we will be able to still match capitalization
;typos.

(while (setq oneLine (read-line fileData)) ;we loop through each line of the file

(setq listed (read (strcat "(" oneLine ")")));here is a nice trick. Each line in the
;lookup file has the data written between double quotes. We want to turn a line into
;a list of two members with the first member being the textToLookFor and the second
;member being the newText that will update theTextToLookFor.

(setq textToLookFor (strcase (car listed)))
(setq newText (nth 1 listed));nth 1 is the equivalent of cadr.

(if (= textToLookFor textEntityContent);look for a string match
(entmod (subst (cons 1 newText) (assoc 1 textEntity) textEntity))
;update the text content with the usual entmod+subst combo
;Note that here (cons 1 newText) is mandatory, as '(1 . newText) doesn't work.

);end of the if

);end of the while loop that goes thourgh each line of the file

(close fileData); close the file after reaching the end otherwise the next while
;will not loop through the file again

(setq pointer (1+ pointer));increment the pointer
); end of the repeat loop

) ;end of defun

(princ "\nProTranslator has finished.")
(princ)

The ProTranslator.dat lookup file looks like this (it translates from left to right):
Quote
"vis" "screw"
"plaque" "plate"
"tige" "rod"
« Last Edit: July 19, 2007, 01:27:02 PM by zibidi »

BazzaCAD

  • Guest
Re: [WIP] Text translator
« Reply #1 on: July 18, 2007, 01:15:19 PM »
That's a great idea.
I wonder if you could use Google Translation tools instead of a text file....
But I'm guessing you want to have control over what the word will be translated to.

zibidi

  • Guest
Re: [WIP] Text translator
« Reply #2 on: July 18, 2007, 01:17:27 PM »
Yes I want to have control over the translation. There are some technical terms that google is incapable of translating.

My repeat loop is fine, it is the way I go through listOfText which is crap. I need to change that.
« Last Edit: July 18, 2007, 01:21:06 PM by zibidi »

T.Willey

  • Needs a day job
  • Posts: 5251
Re: [WIP] Text translator
« Reply #3 on: July 18, 2007, 01:19:01 PM »
The alert won't work because you are giving it a number, and it wants a string.  Try
Code: [Select]
(alert (itoa (sslength listofText)))
A better way, IMO, would be to create an associated list of the text values from your text file.  This way you are not reading the text file with each text entity that is in your drawing.

As far as your repeat only going once, it looks like it should go through all entities.  The only thing I can think of is maybe it is erroring some where.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

zibidi

  • Guest
Re: [WIP] Text translator
« Reply #4 on: July 18, 2007, 01:27:12 PM »
Thanks, I didn't know that autolisp was not capable of automatically transforming an integer into a string.

For your optimized way, I will implement that in a next iteration, first I'd like to have something running, then I will do as you said. You are right it is much better to do it your way, but currently I don't know how to achieve that.

EDIT: I don't understand how increments/decrments work.
Code: [Select]
(setq pointer (1- pointer))This doesn't work  :-(

EDIT: actually it works. I had defined pointer as being a local variable, that's why it didn't work.

Therefore:
I don't understand how local variables work in autolisp.  :lol: (but I don't really care right now)


EDIT:
I can only go through the file once. When I added a "close fileData" it got the following error:
Quote
; error: stream is closed: #<FILE internal>
Does this means that the file is already closed? If so, why can't I loop again through it???

EDIT: File looping fixed!
I had to move the file opening statement inside the repeat. Because I wasn't opening it anymore, so no lines could be read from it  :ugly:
« Last Edit: July 18, 2007, 01:56:14 PM by zibidi »

zibidi

  • Guest
Re: [WIP] Text translator
« Reply #5 on: July 18, 2007, 02:48:47 PM »
I don't understand why it's not working:
Code: [Select]
(defun C:FR (/ )

(setq path2file (findfile "ProTranslator.dat")) ;path to the data file

(setq listOfText (ssget "_X" '((0 . "*TEXT")))) ;fetch all the text entities on the drawing

;(alert (itoa (sslength listofText)))
;To display a number in alert box, you have to first make it into a string.

(setq pointer 0);that's the pointer inside the listOfText. Lists begin with an index of 0

(repeat (setq n (sslength listOfText))
(setq fileData (open path2file "r")) ;open the data file and assign it to fileData
(setq textEntity (entget (ssname listOfText pointer)))
(setq textEntityContent (cdr (assoc 1 textEntity)))

(while (setq oneLine (read-line fileData)) ;we loop through each line of the file
(setq listed (read (strcat "(" oneLine ")")))

(setq textToLookFor (car listed))
(setq newText (nth 1 listed))

(if (= textToLookFor textEntityContent)
(entmod (subst '(1 . newText) (assoc 1 textEntity) textEntity))
);end of the if

);end of the while loop that goes thourgh each line of the file

(close fileData); close the file after reaching the end otherwise the next while
;will not loop through the file again

(setq pointer (1+ pointer));increment the pointer
); end of the repeat loop

(alert "Script finished")
) ;end of defun
The match detection works, I have tried with some test data, but when entmod gets in action, autocad throws the following error:
Quote
; error: bad DXF group: (1 . NEWTEXT)

EDIT:
when I replace the entmod statement with the following:
Code: [Select]
(entmod (subst '(1 . "updated") (assoc 1 textEntity) textEntity))It works, the text gets "updated". So it is the evaluation of newText that is not happening.
« Last Edit: July 18, 2007, 02:51:39 PM by zibidi »

ronjonp

  • Needs a day job
  • Posts: 7526
Re: [WIP] Text translator
« Reply #6 on: July 18, 2007, 02:54:12 PM »
Try this:

Code: [Select]
(subst ([color=red]cons [/color]1 newText) (assoc 1 textEntity) textEntity)

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

zibidi

  • Guest
Re: [WIP] Text translator
« Reply #7 on: July 18, 2007, 03:01:44 PM »
Excellent!!!! Thanks a gazillion ronjonp. I forgot that I could define a DXF group that way.

EDIT: I'd like to add the following feature: during matching test, I 'd like to male the textEntityContent all smallcaps so that it is easier for me to maintain a lookup file. Is there a command/function that transforms "PlaQue" into "plaque"? because I know that there will we typos in the drawings and I don't want to add a new line in the lookup file because the draftsman badly typed a word.

EDIT: the next iteration would be to add a kind of regexp that would enable to update text that has been appended to a dimension for instance, but that will wait a little bit  :-P
« Last Edit: July 18, 2007, 03:27:23 PM by zibidi »

T.Willey

  • Needs a day job
  • Posts: 5251
Re: [SOLVED] Text translator
« Reply #8 on: July 18, 2007, 03:26:43 PM »
Look at 'strcase'.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

zibidi

  • Guest
Re: [SOLVED] Text translator
« Reply #9 on: July 18, 2007, 03:29:19 PM »
That's exactly what I was looking for! Thanks Wiley  :wink:

T.Willey

  • Needs a day job
  • Posts: 5251
Re: [SOLVED] Text translator
« Reply #10 on: July 18, 2007, 03:33:38 PM »
That's exactly what I was looking for! Thanks Wiley  :wink:
You're welcome.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

zibidi

  • Guest
Re: [SOLVED] Text translator
« Reply #11 on: July 18, 2007, 05:00:47 PM »
 :pissed: I am having problems in real-life drawings. AutoCAD keeps throwing me the following error:
Quote
; error: bad argument type: consp nil
The error occurs at the (if (=... line where the matching is tested.

On one drawing, autocad updated one text entity, and then throwed the error. On some other drawings, it happends when loading the drawing. This is completely nonsense  :realmad:

In test drawings, with dummy text it works perfectly.

EDIT: I must have edited something by mistake, because it doesn't work anymore even on a single dummy text entity on a fresh new drawing.


EDIT2: actually it seems that it is the data in my lookup file which is making the lisp crash. That is really strange. Is there a limitation in the number of chars a variables can hold?


Here is the final code
Code: [Select]
(defun C:PT (/ )

;newlines are marked as \P in autocad text.

(setq path2file (findfile "ProTranslator.dat")) ;path to the data file

(setq listOfText (ssget "_X" '((0 . "*TEXT")))) ;fetch all the text entities on the drawing

;(alert (itoa (sslength listofText)))
;To display a number in alert box, you have to first make it into a string.

(setq pointer 0);that's the pointer inside the listOfText. Lists begin with an index of 0

(repeat (setq n (sslength listOfText))
;count how many text entities have been found, and loop n times
;because of the way we move in our list, we need to redefine n each time we loop

(setq fileData (open path2file "r")) ;open the data file and assign it to fileData

(setq textEntity (entget (ssname listOfText pointer)))
;retrieve the text entity so that we can modify its text attribute using entmod

(setq textEntityContent (strcase (cdr (assoc 1 textEntity))));select the text content from the
;text entity
;strcase converts the string into HIGHCAPS so we will be able to still match capitalization
;typos.

(while (setq oneLine (read-line fileData)) ;we loop through each line of the file

(setq listed (read (strcat "(" oneLine ")")));here is a nice trick. Each line in the
;lookup file has the data written between double quotes. We want to turn a line into
;a list of two members with the first member being the textToLookFor and the second
;member being the newText that will update theTextToLookFor.

(setq textToLookFor (strcase (car listed)))
(setq newText (nth 1 listed));nth 1 is the equivalent of cadr.

(if (= textToLookFor textEntityContent);look for a string match
(entmod (subst (cons 1 newText) (assoc 1 textEntity) textEntity))
;update the text content with the usual entmod+subst combo
;Note that here (cons 1 newText) is mandatory, as '(1 . newText) doesn't work.

);end of the if

);end of the while loop that goes thourgh each line of the file

(close fileData); close the file after reaching the end otherwise the next while
;will not loop through the file again

(setq pointer (1+ pointer));increment the pointer
); end of the repeat loop
(princ "\nProTranslator has finished.")
(princ)
) ;end of defun

« Last Edit: July 19, 2007, 12:18:35 PM by Daron »

T.Willey

  • Needs a day job
  • Posts: 5251
Re: [Bug] Text translator
« Reply #12 on: July 18, 2007, 05:07:29 PM »
The error sounds like you are trying to read from a list with now values (nil variable).  You might want to make sure that the line that gets read is not empty.
Tim

I don't want to ' end-up ', I want to ' become '. - Me

Please think about donating if this post helped you.

zibidi

  • Guest
Re: [Bug] Text translator
« Reply #13 on: July 18, 2007, 05:10:03 PM »
I think there are newline characters that must have been inserted by mistake in the lookup file. I was using notepad to craete the lookup file, I guess I'll have to find myself a new editor, because notepad doesn't show well what characters have been inserted and specially special characters that might come from AutoCAD when I copy and paste the text.

EDIT: it seems to be that. I have created a new lookup file from scratch with only a single line, and it worked. I need to find a better way to enter the text data in the lookup file. I guess I could insert it through the command line in autocad.

i'll work on that tomorrow.
« Last Edit: July 18, 2007, 05:12:55 PM by zibidi »

zibidi

  • Guest
Re: [Bug] Text translator
« Reply #14 on: July 18, 2007, 05:40:19 PM »
It annoys  me,  so let's do it now!

I have added a variable that detects whether or not a match for a given text entity has been found. However when testing if a match was found, here is the code:
Code: [Select]
(setq matchFound "false") ;we intialiaze the variable to false

...some initial code already posted...

(if (= matchFound "false")
(progn ;progn is used to evalutate more than one expression with an if block

;(princ (strcat "\nThe text: " textToLookFor " has no entry in the lookup file"))
(alert "there was a problem")
)
);end of the if when matchFound is "false"

However the code I posted right above never shows the alert box to tell me a match has not been found, although matchFound is set to false.

If I update the code to:
Code: [Select]
(if (= "false" "false")
(progn ;progn is used to evalutate more than one expression with an if block

(alert "there was a problem")
)
);end of the if when matchFound is "false"
Then this works, well you know what I was testing.

So why is (if (= matchFound "false") not evaluating correctly?


EDIT: okay I have forgotten to add a progn somewhere in an if block. I'll keep you updated.
« Last Edit: July 18, 2007, 05:45:58 PM by zibidi »