Substitute character in a string

Using Nyquist scripts in Audacity.
Post and download new plug-ins.
Forum rules
If you require help using Audacity, please post on the forum board relevant to your operating system:
Windows
Mac OS X
GNU/Linux and Unix-like
Post Reply
steve
Site Admin
Posts: 81653
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Substitute character in a string

Post by steve » Fri Oct 29, 2010 7:34 pm

Nyquist does not appear to have a function for substituting characters in a string, so here's a function to do just that.

Code: Select all

;; substitute character in string

(defun subst-char-string (string old new)
   (setq newstring "") ; initialise the new string
   (dotimes (i (length string))
      (let ((ch (char string i))) ; ch is the next character in the string
         (if (char= ch old)(setq ch new))
         (setq newstring (strcat newstring (string ch))))) ; add character to string
   newstring)

(print (subst-char-string "Hello World" '#space '- ))
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

edgar-rft
Posts: 347
Joined: Sun Jan 20, 2008 12:03 am
Operating System: Please select

Re: Substitute character in a string

Post by edgar-rft » Sat Oct 30, 2010 3:26 am

I'm quite sure you know, but the function above pollutes the global namespace by creating a global variable named "newstring", it would be better to make "newstring" al local "let" variable. Here is what I usually write:

Code: Select all

(defmacro string-append (variable &rest strings)
  `(setq ,variable (strcat ,variable ,@strings)))

(defun subst-char-string (string old-char new-char)
  (cond ((not (stringp string))
         (error "subst-char-string: not a string" string))
        ((not (characterp old-char))
         (error "subst-char-string: not a character" old-char))
        ((not (characterp new-char))
         (error "subst-char-string: not a character" new-char))
        (t
         (let ((end (length string))
               (result ""))
           (dotimes (index end)
             (let ((current-char (char string index)))
               (if (char= old-char current-char)
                   (string-append result (string new-char))
                   (string-append result (string current-char)))))
           result))))

(print (subst-char-string "Hello World" #space #-)) => "Hello-World"
The local "end" variable is not really necessary, because "dotimes" pre-evaluates its termination-test value and stores it in an internal local variable, but with more complicated "dotimes" loops the "end" variable makes the code more readable [at least for me].

BTW: The unicode research says: (char <string> <index>) is safe with multi-byte unicode characters.

- edgar

steve
Site Admin
Posts: 81653
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: Substitute character in a string

Post by steve » Sat Oct 30, 2010 1:08 pm

Good point re. 'newstring' being a global variable.

I'm a bit cautious about creating functions that depend on other functions/macros as it seems a bit too easy to forget about the dependency. For short functions I generally prefer to nest the dependant function to ensure that they stay together (unless of course the function/macro is also used elsewhere). Is there anything wrong with this approach?

Code: Select all

(defun subst-char-string (string old-char new-char)
   ; nested macro
   (defmacro string-append (variable &rest strings)
     `(setq ,variable (strcat ,variable ,@strings)))
   ; back to main function code
   (let ((end (length string))
            (result ""))
      (dotimes (index end)
         (let ((current-char (char string index)))
            (if (char= old-char current-char)
               (string-append result (string new-char))
               (string-append result (string current-char)))))
      result))

(print (subst-char-string "Hello World" '#space '#-)) ; => "Hello-World"
or simply:

Code: Select all

(defun subst-char-string (string old new)
   (let ((newstring "")) ; initialise the new string
      (dotimes (i (length string))
         (let ((ch (char string i))) ; ch is the next character in the string
            (if (char= ch old)(setq ch new))
            (setq newstring (strcat newstring (string ch))))) ; add character to string
      newstring))

(print (subst-char-string "Hello World" '#space '#- )) ; =>Hello-World
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

edgar-rft
Posts: 347
Joined: Sun Jan 20, 2008 12:03 am
Operating System: Please select

Re: Substitute character in a string

Post by edgar-rft » Sat Oct 30, 2010 5:19 pm

stevethefiddle wrote:For short functions I generally prefer to nest the dependant function to ensure that they stay together (unless of course the function/macro is also used elsewhere). Is there anything wrong with this approach?
Of course there's nothing wrong. The "string-append" is a simplified version of one of my standard text macros and I just simply was to lazy to fiddle it into the function's code, that's all [sorry if you had expexted more secret science behind that ;) ] ...

- edgar

steve
Site Admin
Posts: 81653
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: Substitute character in a string

Post by steve » Sun Oct 31, 2010 9:33 pm

edgar-rft wrote:the function above pollutes the global namespace by creating a global variable named "newstring", it would be better to make "newstring" al local "let" variable.
I've just been reading about functions in the xlisp manual - it looks like an another alternative would be to make 'newstring' a local variable by including it as &aux argument in the function, for example:

Code: Select all

(defun subst-char-string (string old new &aux (newstring ""))
   (dotimes (i (length string))
      (let ((ch (char string i))) ; ch is the next character in the string
         (if (char= ch old)(setq ch new))
         (setq newstring (strcat newstring (string ch))))) ; add character to string
   newstring)
I don't recall ever seeing this method used in any plug-ins, but it looks like a neat way to set local variables if there are only a few.
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

agua
Posts: 127
Joined: Wed Mar 14, 2018 3:15 am
Operating System: Windows 7

Re: Substitute character in a string

Post by agua » Thu Jul 18, 2019 7:28 pm

Hi Steve and Edgar. Using any of those code versions for the substitution, I'm getting an error. Any idea what I am doing wrong ?

Here is the following error in Debug window :

error: illegal character after # - 115
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823f68>
#\#
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
1> error: unbound variable - PACE
if continued: try evaluating symbol again
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823f68>
#\#
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
2> error: illegal character after # - 45
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823ee8>
#\#
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823f68>
#\#
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
3> error: misplaced right paren
Function: #<Subr-(null): #13c0c7e0>
Arguments:
#<File-Stream: #4823ee8>
#\)
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823ee8>
#\#
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823f68>
#\#
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
4> error: misplaced right paren
Function: #<Subr-(null): #13c0c7e0>
Arguments:
#<File-Stream: #4823ee8>
#\)
Function: #<Subr-(null): #13c0c7e0>
Arguments:
#<File-Stream: #4823ee8>
#\)
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823ee8>
#\#
Function: #<Subr-(null): #13c0c840>
Arguments:
#<File-Stream: #4823f68>
#\#
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
Function: #<Subr-(null): #13c0c800>
Arguments:
#<File-Stream: #4823f68>
#\(
5> 4> 3> 2> 1>

agua
Posts: 127
Joined: Wed Mar 14, 2018 3:15 am
Operating System: Windows 7

Re: Substitute character in a string

Post by agua » Thu Jul 18, 2019 7:34 pm

OK, I think I found the trouble. Everything went fine when I change #space and #- by #\space and #\-.

steve
Site Admin
Posts: 81653
Joined: Sat Dec 01, 2007 11:43 am
Operating System: Linux *buntu

Re: Substitute character in a string

Post by steve » Thu Jul 18, 2019 7:59 pm

agua wrote:
Thu Jul 18, 2019 7:34 pm
OK, I think I found the trouble. Everything went fine when I change #space and #- by #\space and #\-.
That's correct.
This is a very old topic, and I guess that during one of the forum updates over the years, the backslashes got lost in the forum's database. I don't think these code samples would have ever worked without the backslashes.
9/10 questions are answered in the FREQUENTLY ASKED QUESTIONS (FAQ)

Post Reply