Lesson 10
Strings & Printing

This lesson deals with several related subjects including text strings, converting between strings and numbers, printing to screen, and printing text in a drawing.  Strings are just one of several different data types that AutoLISP uses, so a brief discussion of the various data types will help you appreciate the distinction between strings and other data types.

Date types

You have already been introduced to the distinction between integers and reals in Lesson 2.  Strings are also an important data type, entirely different from integers and reals.

When submitting arguments to a function, they must be of the correct data type.  For example, you cannot submit strings to arithmetic or math functions.  In other words, an expression such as (* "five" "three") does not return 15.  Rather, it returns the error message "bad argument type" which indicates that you have used an invalid data type for one or more of the arguments..  Similarly, you cannot submit integers or reals to string functions.  The expression (strcat 5 3) would also return the error message "bad argument type" because the strcat function (which joins strings into a single string) requires arguments that are already strings.

The various types you will work with in AutoLISP are shown in the table below.  The second column contains the symbol returned when the data type is submitted to the type function.  For example, in the case of an integer, the expression (type 19) returns INT.  See type in "7 - Logic & category tests."
 

Data type Symbol
returned
by type
Description
integer INT A whole number such as 5, -18, or 0
real REAL A floating point number such as 5.25, -9.0, or 0.0
string STR A text string such as "hello", "main street", or "120"
list LIST A list such as (8 10 "twelve" var).  Created with the list function, as well as other functions.
symbol SYM A pointer to a value in memory.  Variable names and function names are symbols.
selection set PICKSET A collection of selected items.  Created with the ssget function, as well as other functions.
entity name ENAME A pointer to the memory location holding the beginning of a description of a graphic entity
file descriptor FILE A pointer to the memory location of a file buffer
subroutine SUBR Pre-defined routines such as setq, *, and polar

Text strings

A text string is any group of characters treated as a string (rather than a number, symbol, etc.).  Here are several examples of text strings.  Notice that they all have quotation marks surrounding them to indicate that they are strings.

    "hello"   "good bye"   "fourteen"   "14"   "14-A"

There are several AutoLISP functions which manipulate strings.  See "10 - Text strings" in the Function definitions.  In particular, you should look up the following functions because they are used either in previous sample programs or in the sample programs in this lesson:

Converting between strings and numbers

It is often necessary to convert a number to a string or vice versa.  See "12 - Converting data types" in the Function definitions.  Conversion is needed, for example, when concatenating a sentence to display on screen or send to a file.  If the sentence contains numbers (integers or reals), they would have to be converted into strings in order to be valid arguments for the strcat function.

In particular, you should look up the following functions:


Printing to the text screen

"Printing to the text screen" means displaying text in AutoCAD's command prompt area, which can then be reviewed a screen at a time by pressing F2.  There are several functions which print to the text screen, summarized in the table in "11 - Printing to screen" in the Function definitions.

The printing function that you will use most often is the princ function -- the only one that combines these two helpful characteristics:

The various control characters that princ obeys are listed under princ in "11 - Printing to screen" in the Function definitions.

The control character that you will use most often is the "new line" character ("\n").  It appeared in all of the sample programs so far, since it is used at the beginning of every prompt.  When you use this control character, make sure that you

When your program needs to flip to the text screen (to display several lines of print, a table, etc.), use either the textscr or the textpage function.  When it needs to flip back to the drawing on the graphics screen, use the graphscr function.

Printing several items

The princ function takes only one argument, which can be a string or a number or, of course, a variable holding a string or number.  When you have several items to print, you have three different approaches to choose from:  repeating the princ function, concatenation, or using princ in a foreach loop.

Repeating the princ function

When you have just a few items to print to screen (perhaps less than five), you can simply repeat the princ function.  Suppose you need to print a sentence with two absolute strings and two variables such as "Plate contains 36 holes with an average diameter of 1.125."  If the variable hol contains the number of holes and the variable avdia contains the average diameter, the following four princ expressions will print the desired sentence:

    (princ "\nPlate contains ")
    (princ hol)
    (princ " holes with an average diameter of ")
    (princ avdia)

Notice that there are spaces at the end of the first string and at both the beginning and end of the second string.

Concatenation in a single princ function

The same sentence illustrated above could be printed with one princ function, but the four parts would need to be concatenated with the strcat function into one long string, as follows:

    (princ (strcat "\nPlate contains " (itoa hol) " holes with an average diameter of " (rtos  avdia 2 3)))

Notice that the number of holes (an integer) is converted to a string with the itoa function, and the average diameter (a real) is converted to a string with the rtos function.

Using princ in a foreach loop

The same sentence illustrated above could be printed by using princ in a foreach loop.  A foreach loop becomes a more efficient way to print longer sentences made up of many items (perhaps five or more).  However, for sake of comparison we will illustrate this approach with the same sentence used above.

    (foreach v
       (list "\nPlate contains " hol " holes with an average diameter of " avdia)
       (princ v))

This method of printing longer sentences has two advantages.  First, the appearance of the sentence in the program looks more like the on-screen result than either of the previous methods.  Second, fewer functions are used and thus the programming is more efficient, especially as the number of elements increases.

This method is illustrated in the sample program below called strfacts, section 40, which prints six lines made up of 14 elements.

Practice session

Below are four examples to be printed to screen.  Use princ.  Also use the appropriate number conversion function (itoa or rtos), and the backslash-n to print each example so it appears exactly as shown. The regular text can be programmed as constants; the items in italics should be retrieved from variables.  Complete each example using all three methods explained above.  The first example is completed for you.

15 blocks found on layer Electrical

Preparation:
(setq bnum 15 lname "Electrical")
First method:
(princ bnum)(princ " blocks found on layer ")(princ lname)    Note: If you are typing these examples in at the command prompt rather than placing them in a file, you will need to "gang up" your princ statements on one line, with no spaces between closing and opening parentheses as shown above, in order to achieve the desired result.
Second method:
(princ (strcat (itoa bnum) " blocks found on layer " lname))
Third method:
(foreach v (list bnum " blocks found on layer " lname) (princ v))
This item located at 3.35,18.00,4.50.   (Use three separate variables for the coordinates, and include the period at the end.)

Size: 5/8
Stroke: 2.75
Duty: Medium
Connector: Standard

Center of gravity 18.37 feet from pivot, at elevation of 45 feet.   ("feet" is in a separate variable)

Printing text in a drawing

To place text in a drawing, use the command function with the TEXT command (rather than DTEXT or MTEXT).  For example, the following expression places the string "READ ME", center justified at 4,3 with a height of .375 and zero rotation.

    (command ".text" "C" (list 4 3) 0.375 0 "READ ME")

What do you do when you need to place several lines of text in a drawing.  Since the DTEXT and MTEXT commands can work with multiple lines of text, you might assume that they are the appropriate commands to use.  But it is simpler to use the regular TEXT command inside a repeat, while, or foreach loop.

Padding: adding spaces to line up columns

Many times you need to place numbers or other text in a table so that the columns line up.  If you are printing multiple lines to the text screen and want columns to line up, all you need to consider is the number of characters needed in each column since all the text screen fonts that are available (under "Preferences") are mono spaced.

For example, if the table is to contain left justified words, then you will want to add trailing spaces so that each "word" has the appropriate number of characters for its column.

Or, if you are trying to line up the decimal points in a column of numbers, you will need to have a consistent number of characters both before and after the decimal point.  To get a consistent number of characters after the decimal point, you can use the rtos function to specify the number of decimal digits.  The following example calls for 4 decimal digits.

    (princ (rtos len 2 4))

You will also need to add leading spaces.  Suppose, for example, that you have several strings that range in length from 4 to 8 characters.  You want to pad them so they are all 10 characters long.  In the following three sample algorithms, the string is contained in variable str, it is padded, then reassigned to variable str.  All three approaches accomplish the same thing when the original string is 10 characters or less.  But they differ in the way they handle longer strings.

Algorithm 1
(repeat (- 10 (strlen str)) (setq str (strcat " " str)))
Algorithm 2
(setq str (strcat "          " str))    ----    <10 spaces between the quotation marks>
(setq str (substr str (- (strlen str) 9)))
Algorithm 3
(setq str (strcat "          " (substr str 1 10)))    ----    <10 spaces between the quotation marks>
(setq str (substr str (- (strlen str) 9)))
Submitting the string "hello" to each algorithm returns "     hello" (5 leading spaces).  However, if the original string is longer than 10 characters:
Algorithm 1
Preserves all of the original characters, because the first argument to the repeat function would be negative, causing the repeat function to do nothing.
Algorithm 2
Preserves only the right 10 characters of the original string.
Algorithm 3
Preserves only the left 10 characters of the original string.
If the text is going to be placed in a drawing, you will need to use a mono spaced font such as Monotxt or Monospac821BT.

See the sample programs in Lesson 7 (bctable, section 40) and Lesson 9 (monthly, leading-spaces-routine) for illustrations of padding.

Initget with strings

In previous lessons we discussed the use of initget with integer arguments to disallow certain types of input to the get-functions.  We also discussed the use of initget with string arguments to limit the accepted responses to the getkword function.  It is possible to use both integer and string arguments together.

Suppose you want to get a positive number from the user, but you also want the user to have the option of entering one or more keywords such as Minimum and Maximum.  You could use initget as follows:

    (initget 4 "MInimum MAximum")
    (getreal "\nEnter distance (or Minimum/Maximum): ")

The above allows the user to enter either a number (which must be positive) or one of the two strings "MI" or "MA" (or, of course, the complete word).

This sort of usage of initget (with the getpoint function) is illustrated in the previous lesson in the sample program called curvtext (section 30) and below in the sample program called stext (section 20).

Strings and printing in earlier sample programs

Several programs in previous lessons have already illustrated the use of strings and printing.

Sample program 1, sysvars

The program below illustrates the strcat function.  It sets the system variable "modemacro" and thus displays the current values of certain other system variables in the status line at the bottom of the AutoCAD screen.  The value of the string assigned to "modemacro" is evaluated frequently so that, whenever one of the system variables is changed, its new value appears immediately in the status line.

This program is unique in that it uses no user defined variables.  Instead, it retrieves values from several system variables which become part of a larger concatenated string assigned to the "modemacro" system variable.  Each of the substrings contains macro expressions (starting with $) written in the DIESEL language.  These expressions are explained in the chapter on "status line configuration" in the AutoCAD Customization Guide.  The forward slash (/) at the end of four of the lines merely serves as a separator in the status line.

As a result of displaying these values, part of the rest of the status line may end up off screen.  To fix this you could remove one or more of the lines in the strcat expression, or abbreviate the readouts.

The status line displays five settings:

------ marker ------ beginning of working program ------ try it out ------

;|  SYSVARS, short for SYStem VARiableS
    Copyright © 1998 Ronald W. Leigh
    Input: none
    Output: displays status of certain system variables   |;

(defun c:sysvars ()
(setvar "modemacro"
  (strcat
    "UCS=$(getvar,ucsname) / "
    "Snap=$(getvar,snapunit) / "
    "LTScale=$(getvar,ltscale) / "
    "TextStyle=$(getvar,textstyle) / "
    "Dimscale=$(rtos,$(getvar,dimscale),3,2)"
  )
)
(princ)
)

-------- marker -------- end of working program -------- try it out --------
 

Sample program 2, strfacts

This program, named strfacts, analyzes a string (a sentence entered by the user) and reports five facts: the length of the string, the number of words, the number of spaces, the number of punctuation marks, and the average word length.

Section 20 strips leading and trailing spaces from the string entered by the user.  This guarantees that the actual string analyzed by the program begins and ends with something other than a space.  Then section 30 analyzes the string in four steps: total length, spaces and words, punctuation marks, and average word length.

Total length.  The first line in section 30 obtains the length of the string simply by using the strlen function.

Spaces and words.  The first repeat loop in section 30 counts spaces and words.  The repeat loop executes once for each character in the string (except the last character).  The variable indx is initialized at zero, but then is incremented at the beginning of the loop.  Thus each subsequent time through the loop, the next character is extracted by the substr function.  If that character is a space, the variable spaces is incremented.  If that character is not a space and the next character is a space, then the variable words is incremented.  Of course, this method of identifying words does not work for the last word because the last character cannot be a space (trailing spaces were stripped earlier).  This is why the variable words is initialized at 1 rather than zero.

Punctuation marks.  The second repeat loop in section 30 counts punctuation marks.  It detects the following punctuation marks by looking for certain ascii codes.  (See the ascii table in the glossary.)

   - exclamation point (!),  ascii 33
   - double quotation mark ("),  ascii 34
   - single quotation mark ('),  ascii 39
   - comma (,),  ascii 44
   - period (.),  ascii 46
   - colon (:),  ascii 58, and
   - semicolon (;),  ascii 59.

This loop looks at every character in the string.  It finds punctuation marks by using the function member, which is explained in a later lesson.  Briefly, this loop looks at each character, gets that characters ascii code, then finds out of that code is a member of the list of ascii codes shown above.  When it finds that the ascii code is a member of the list, it increments the variable punct.

Average word length.  This is a simple calculation which subtracts the number spaces and punctuation marks from the total length of the string, then divides by the number of words.

------ marker ------ beginning of working program ------ try it out ------

;|  STRFACTS, short for STRing FACTS
    Copyright © 1998 Ronald W. Leigh
    Input: User enters a sentence
    Output: Program analyzes sentence and reports length,
     # of words, # of spaces, # of punctuation marks,
     and average word length
Variables:
awl     Average word length
indx    Index for repeat loops
len     Length of string
punct   Number of punctuation marks
str     String to be analyzed
spaces  Number of spaces
words   Number of words              |;

;10====PROGRAM, GET STRING

(defun c:strfacts (/ awl indx len punct str spaces words)
(textscr)
(setq str (getstring 1 "\nEnter string to be analyzed: "))

;20====STRIP LEADING AND TRAILING SPACES

(while (= 32 (ascii str))
  (setq str (substr str 2)))
(while (= " " (substr str (strlen str) 1))
  (setq str (substr str 1 (1- (strlen str)))))

;30====ANALYZE LENGTH, SPACES, WORDS, PUNCT. MARKS, AVER. WORD LENGTH

(setq len (strlen str))
(setq indx 0 spaces 0 words 1)
(repeat (1- len)
  (setq indx (1+ indx))
  (if (= " " (substr str indx 1)) (setq spaces (1+ spaces)))
  (if (and (/= " " (substr str indx 1)) (= " " (substr str (1+ indx) 1)))
    (setq words (1+ words))))
(setq indx 0 punct 0)
(repeat len
  (setq indx (1+ indx))
  (if (member (ascii (substr str indx 1)) (list 33 34 39 44 46 58 59))
    (setq punct (1+ punct))))
(setq awl (/ (- len spaces punct) (float words)))

;40====REPORT

(foreach v (list
    "\n  --->" str "<---"
    "\nTotal length = " len " characters."
    "\nNumber of words = " words
    "\nNumber of spaces = " spaces
    "\nNumber of punctuation marks = " punct
    "\nAverage word length = " (rtos awl 2 4))
  (princ v))

(princ)
)

-------- marker -------- end of working program -------- try it out --------
 

Sample program 3, stext

This program allows you to control the vertical spacing when you place several lines of text in a drawing.  For purposes of discussion we will define vertical spacing as a ratio:  the distance between baselines divided by the height of the text (capitals).

When you use AutoCAD's built in text commands to place several lines of text in an AutoCAD drawing, you have little control over the vertical spacing of the text.  Neither the DTEXT command nor the MTEXT command lets you specify vertical spacing.  Even the simple TEXT command (when you click through the text location prompt in order to place the next line of text below the previous line of text) does not let you specify vertical spacing.  In each of these cases, the vertical spacing is controlled by the font in use.  The vertical spacing set by most fonts ranges from 1.6 to 1.7.

This spacing is rather close, and may be suitable for several lines of text in a note.  But if you need to fill in the columns of an existing table or chart (where there will be a horizontal line entity between each text entity), such spacing is too close.  In addition, predrawn tables and charts often have their lines spaced at "round" increments such as .5 inch or 12 mm.  So when you want to fill in a column in a table, the procedure can be rather cumbersome.  You could place each line of text separately.  Or you could place one line, array it to get the desired spacing, then use DDEDIT to change the text in each line.

The stext program solves the above problem.  It lets you specify vertical spacing, then enter multiple lines of text.  The result is individual lines of text like those produced by the TEXT or DTEXT command, rather than an associated group of lines like those produced by MTEXT.  Since this command is especially designed to place text in an existing table or chart, the options are kept simple.  For example, in section 20, there are no options for "fit" or "aligned" text.  Instead, there are only options for center and right justified text, as well as the default left justified.  Also, if you want to change the text style, you must use the STYLE command or the TEXT command to do so before running stext.

Text height is determined in two ways.  If a text style is defined with a non-zero height, then that height is used automatically whenever one of the text commands is used.  But if the text style is defined with a zero height, then the user is asked to enter a height each time the text command is used.  In section 30, the current text style is analyzed to determine if it has a fixed text height.  The tblsearch function (explained in a later lesson) is used to retrieve this information, and the defined height is saved in variable defhi.  If defhi is zero, the the user is asked to enter a height (which, by default is taken from system variable "textsize").  If defhi is non-zero, then its value is assigned to variable h and a message is displayed which informs the user of the fixed height.

In section 50, the default line spacing is set at twice the text height.  This, of course, can be changed by the user.

In section 60, the while loop keeps repeating the prompt for the next line of text until the user hits 'Enter' (in which case the getstring function returns "").  When it comes to actually placing the text in the drawing, four different command functions are needed because the TEXT command operates differently depending on (1) whether a starting point is picked (indicating left justification) or whether "C" or "R" is entered, and (2) whether the current text style has a fixed height.

------ marker ------ beginning of working program ------ try it out ------

;|  STEXT, short for Spaced TEXT
    Copyright © 1989,1998 Ronald W. Leigh
    Input: Text location, justification, height,
           angle, vertical spacing, and text
    Output: Lines of text at requested spacing
Variables:
d     Degrees in baseline angle
defhi Style defined height
dir   Direction to start of next line
h     Text height
opt   Option (point or "C" or "R")
p     Starting point of text
rot   Text rotation angle
temp  Temporary input
ts    Text string                  |;
vsp   Text vertical spacing

;10====PROGRAM, SETUP

(defun c:stext (/ d defhi dir h opt p rot temp ts vsp)
(setq pi 3.1415926535897932385)
(setq oom (getvar "osmode") obm (getvar "blipmode"))
(setvar "cmdecho" 0)
(setvar "osmode" 0)
(graphscr)

;20====GET START POINT/JUSTIFICATION

(initget 1 "C R")
(setq opt (getpoint "\nStart point or Center/Right (C/R): "))
(cond
  ((= opt "C") (setq p (getpoint "\nCenter: ")))
  ((= opt "R") (setq p (getpoint "\nEndpoint: ")))
  (1 (setq p opt)))

;30====GET HEIGHT

(setq defhi
  (cdr (assoc 40 (tblsearch "style" (getvar "textstyle")))))
(if (zerop defhi)
  (progn
    (setq h (getdist p (strcat
     "\nHeight <" (rtos (getvar "textsize")) ">: ")))
    (if (null h)
      (setq h (getvar "textsize"))
      (setvar "textsize" h)))
  (progn
    (setq h defhi)
    (princ (strcat "\n(Fixed height = " (rtos h) ")"))))

;40====GET ROTATION ANGLE

(setq rot (getangle p "\nRotation angle <0.0>: "))
(if (null rot) (setq rot 0.0))
(setq dir (+ rot (* pi 1.5)))
(setq rot (* rot (/ 180 pi)))

;50====GET VERTICAL SPACING

(setq vsp (* h 2))
(setq temp (getdist p (strcat
 "\nLine spacing (neg. for ascending lines) <" (rtos vsp) ">: ")))
(if temp (setq vsp temp))

;60====GET LINES OF TEXT AND PLACE IN DRAWING

(setvar "blipmode" 0)
(while (/= "" (setq ts (getstring 1 "\nText (or 'Enter' to quit): ")))
  (if (or (= opt "C") (= opt "R"))
    (if (zerop defhi)
      (command ".text" opt p h rot ts)
      (command ".text" opt p rot ts))
    (if (zerop defhi)
      (command ".text" p h rot ts)
      (command ".text" p rot ts)))
  (setq p (polar p dir vsp))
)

;70====RESET

(setvar "osmode" oom)
(setvar "blipmode" obm)
(setvar "cmdecho" 1)
(princ))

-------- marker -------- end of working program -------- try it out --------

 

HOME

Copyright © 1988, 1998 Ronald W. Leigh