NewLisp for VisualNEO Win. Part 3. Strings

In newLISP, the data types strings, one-dimensional arrays and lists have a lot in common: they are all sequences of some elements – in a specific order. It is no surprise that many of the newLISP’s built-in functions can be applied to strings, arrays and lists.

As the developer of newLISP, Lutz Mueller wrote:

“Many of newLISP’s built-in functions are polymorphic and accept a variety of data types and optional parameters. This greatly reduces the number of functions and syntactic forms necessary to learn and implement.”

As an example, the function ‘length’ can be applied to:

1. a string:

(length “Hello World”)
→ 11

2. an one-dimensional array:

(length ‘(1 2 3 4 5))
→ 5

3. a list:

(length ‘(a b (c d) e))
→ 4

This tutorial is about strings. Why? The newLISP string functions are great for VisualNEO users. Meanwhile we learn -subconsciously- about the possible application of functions on arrays and lists (we will discuss these in later tutorials). Notice that I selected only newLISP functions that have no direct equivalents in VisualNEO. Sometimes VisualNeo and newLISP functions do more or less the same thing. But remember that one of the powerful features of newLISP is combining several functions in one expression.

Assuming you’ve installed the newLISP plugin of Hans-Peter Wickern (https://visualneo.com/product/hpwnewlisp), you will probably know how to implement newLISP code into your VisualNEO script:

hpwNewLispCall "(length {Hello World})" "[DllRetvar]"
Alertbox "Result" "[DllRetvar]"

If necessary, reread my first and second tutorial.

Ok, let’s have a look at some functions that operate on strings.

Section 1. Basic string operations

The newLISP functions ‘lower-case’ and ‘upper-case’ do what we expect and have their VisualNeo equivalents. Two other functions extend the VisualNeo commands.

1.1 ‘reverse’
The function ‘reverse’ reverses a string:

(reverse “the name reinier is a palindrom”)
→ “mordnilap a si reinier eman eht”

1.2 ‘title-case’
To capitalize the first character of a string, after removing the spaces at the beginning and the end of a string:

(title-case (trim ” reinier h. maliepaard    “))
→ “Reinier h. maliepaard”

(what the trim function does, see 1.5.2)

1.3 ‘title-case’ on substrings

If the result string in the previous example should have been “Reinier H. Maliepaard”, we have

– to parse the string into a list of strings
– to map ‘title-case’ to each element of this list and
– to join this modified list into a string

(join (map title-case (parse “reinier h. maliepaard”)) ” “)
→ “Reinier H. Maliepaard”

1.4 Substrings
Extracting substrings from strings is straightforward: count either forwards from the cut (positive integers, 0 inclusive) or backwards from the end (negative integers). Negative indexes are for VisualNeo users an interesting feature.

(“0123456” 0)
→ “0”

Alternative solution:
(first “0123456”)
→ “0”

(“0123456” -1)
→ “6”

Alternative solution:
(last “0123456”)
→ “6”

The function ‘slice’ gives you a new slice of an existing string.

(slice “0123456” -1 1)
→ “6”

(slice “0123456” -2 2)
→ “56”

(slice “0123456” 3)
→ “3456”

(slice “0123456” 3 -1)
→ “345”

(slice “0123456” 3 -2)
→ “34”

You can also use a shorter variant:
– remove ‘slice’ and
– put the range of numbers to the front.

The last example could also be written as

(3 -2 “0123456”)
→ “34”

Notice the use of ‘rest’ as alternative of (slice “0123456” 1 6):

(rest “0123456”)
→ “123456”

which is the same as

(1 “0123456”)
→ “123456”

(3 “0123456”)
→ “3456”

etc.

1.5 Changing the beginnings and/or the ends of strings

1.5.1 ‘chop’
The function ‘chop’ removes characters from the end of a string. Default is removing the last character.

(chop “Hello”)
→ “Hell”

To remove 3 characters from the end, add the parameter 3:

(chop “Hello” 3)
→ “He”

1.5.2 ‘trim’
The function ‘trim’ removes characters from the beginning and the end of a string. Default: removing spaces.

(trim ”        123       “)
→ “123”

(trim  “——123——” “-“)
→ “123”

(trim “——123******” “-” “*”)
→ “123”

(trim “——123******” “-“)
→ “123******”

(trim “——123******” “*”)
→ “——123”

1.6 Modifying strings with ‘setf’ and ‘replace’

1.6.1 ‘setf’
With the function ‘setf’, you can change characters of a string (list and array) by their index numbers. To see how ‘setf’ exactly works, we use a variable, defined with ‘setq’.

;define a variable with ‘setq’
(setq my-string “reinier h. maliepaard”)

;replace the first character ‘r’ (index number 0) with ‘R’
(setf (my-string 0) “R”)
→ “R”

;the original string has been changed
my-string
→ “Reinier”

If you don’t want to modify the original string definitively (hence ‘setf’ is called a destructive function), use the function ‘copy’:

(setf ((setq result-string (copy my-string)) 0) “R”)
→ “R”

my-string
→ “reinier”

result-string
→ “Reinier”

1.6.2 ‘replace’
No surprise, the function ‘replace’ (also destructive) is very powerful using regular expressions (study tutorial 2 for information on basic regular expression syntax). In addition, ‘replace’ with regular expressions also sets the internal variables  system variables $0, $1, $2, up to $15 with the contents of the expressions and subexpressions found. Last but not least, the ‘replace’ function has a ‘replace only the first match’ option.

;the parameter 0 indicates a case-sensitive search
(replace “a” “aAa” “X” 0)
→ “XAX”

;the parameter 1 indicates a case-insensitive search
(replace “a” “aAa” “X” 1)
→ “XXX”

The previous examples can easily be done with VisualNeo’s StrReplace. But the next examples are rather cumbersome to realize in VisualNeo.

;the parameter 0x8000 indicates ‘replace only the first match’ option
(replace “a” “aAa” “X” 0x8000)
→ “XAa”

;now in combination with the regular expression a|A, i.e. match the character ‘a’ or ‘A’
(replace “a|A” “AaA” “X” 0x8000)
→ “XaA”

(replace “a|A” “aaA” “X” 0x8000)
→ “XaA”

;found subexpressions are returned in the system variables $1, $2 etc.
;$3 contains the third subexpression, $2 the second and $1 the first
;so ‘123’ will be returned as ‘321’ and ‘193’ as ‘391’

(setq my-string “—123—193—“)
(replace “(1)(.)(3)” my-string (append $3 $2 $1) 0)
→ “—321—391—”

The function ‘append’ glues strings together: see 2.2

;found expressions are returned in the system variables $0
(replace “t|b|n” “to be or not to be” (upper-case $0) 0)
→ “To Be or NoT To Be”

1.6.3 ‘rotate’

(setq str “0123456”)

;to the right
(rotate str 1)
→ “6012345”

;to the left
(rotate str -1)
→ “1234560”

(rotate str 2)  
→ “5601234”

(rotate str -2)
→ “2345601”


Section 2: making strings

Although VisualNeo has enough tools to make a string, let’s have a short look at how strings can be made in newLISP.

2.1 Build string with the functions ‘sequence’, ‘char’ and ‘join’

(char “a”)
→ 97

(char 97)
→ “a”

(sequence (char “a”) (char “z”))
→ (97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117  118 119 120 121 122)

(map char (sequence (char “a”) (char “z”)))
→ (“a” “b” “c” “d” “e” “f” “g” “h” “i” “j” “k” “l” “m” “n” “o” “p” “q” “r” “s” “t” “u” “v” “w” “x” “y” “z”)

To transform this list of separated strings into one string, use the function ‘join’:

(join (map char (sequence (char “a”) (char “z”))))
→ “abcdefghijklmnopqrstuvwxyz”

To make a CSV string, add an extra parameter to ‘join’:

(join (map char (sequence (char “a”) (char “z”))) “;”)
→ “a;b;c;d;e;f;g;h;i;j;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y;z”

2.2 The function ‘append’ glues strings together
The function ‘append’ works on strings:

(append “Hello” ” world ” “of newLISP!”)
→ “Hello world of newLISP!”

(append “Today ” “it ” “is ” (date))
→ “Today it is Tue Jun 25 13:23:44 2019”

Note that (date) returns a string.

2.3 ‘string’ as powerful alternative to ‘append’
More powerful than ‘append’ is the string function: it converts arguments to strings and append in one step:

(string “The expression ” ‘(sequence 1 10) ” produces – if unquoted! – the list ” (sequence 1 10))
→ “The expression (sequence 1 10) produces – if unquoted! – the list (1 2 3 4 5 6 7 8 9 10)”

2.4 ‘dup’ for character repetitions within a string

(dup “AB” 5)
→ “ABABABABAB”


Section 3: ‘find’ and ‘find-all’

The functions ‘find’ and ‘find-all’ do what their name suggests. These functions are strong tools when combined with regular expressions. A few examples, skipping the applications that resemble the VisualNeo function SearchStr.

;the option 0 in ‘find’ as in other newLISP string functions refers to case-sensitive and 1 to case-insensitive:

(find “cat|dog” “I have a cat” 0)  
→ 9

(find “cat|dog” “I have a CAT” 0)  
→ nil

;case-insensitive
(find “cat|dog” “I have a CAT” 1)  
→ 9

;use an optional offset to search from a specific position, here from the index number 12
(find “cat|dog” “I have a cat and a dog” 0 12)
→ 19


Section 4: 10 problems to learn from…

Problem 1: what’s the last character of a string?

Solution:
(last “A secret message”)
→ e

Problem 2: pick one or more characters from string

Solution:
(select “abcdef” -2 -1 0)
→ “efa”

Problem 3: convert the first character of a string to upper-case and the other characters of that string to lower-case

Solution:
(title-case “bABS” true)
→ “Babs”

Problem 4: trim characters from both sides or trim only one side

Solution:
;trim character from the end
(trim “aaa12345z” “” “z”)
→ “aaa12345”

;trim character from the beginning
(trim “a12345zz” “a” “”)
→ “12345zz”

;trim characters from the beginning and the end
(trim “aa12345zzz” “a” “z”)
→ “12345”

;short default code: trim space from both sides
(trim ” 12345 “)
→ “12345”

Problem 5: replace all characters of a string by a specified character

What to know:
a regular expression that refers to all characters: \.

Solution:
(replace “\.” “abcdef” “X” 1)

→ “XXXXXX”

Problem 6: replace all digits of a string by a specified character

What to know:
a regular expression that refers to numbers: \d

Solution:
(replace “\\d” “a1c2e3” “X” 0)
→ “aXcXeX”

Problem 7: give position of the first character of a string that is included in a given subset

What to know:
;regular expression class of characters:
[x|y|z]

Solution:
(find “[x|y|z]” “abczef” 0)
→ 3

Problem 8: give position of the first character of a string that is not included in a given subset

What to know:
;regular expression class of included characters
[x|y|z]
; regular expression class of excluded characters
[^x|y|z]

Solution:
(find “[^x|y|z]” “zabcxef” 0)
→ 1

Problem 9: encrypt and decrypt a string

(setq secret (encrypt “A secret message” “my secret key”))
→ “,YS\022\006\017\023\017TM\014\022\n\012\030E”

(encrypt secret “my secret key”)
→ “A secret message”

Problem 10: divide up a string into 5 character groups after removing the interpunction characters ! . , and space

(setq secret “A secret message. A secret key, a secret agent!”)
(explode (replace “[,!\. ]” secret “” 0) 5)
→ (“Asecr” “etmes” “sageA” “secre” “tkeya” “secre” “tagen” “t”)

Thank you for reading. Till next time!

Reinier Maliepaard

(last update: 22-07-2019)