How to remove non-alphanumeric characters from a string? I only want to keep numbers and letters, and have thought of building a list of all non-alphanumeric characters and check if each character of the string is a member of the list
Convert the string to a list of characters, filter using the alphanum? predicate, then convert back to a string.
(define (remove-non-alphanum s)
(list->string (filter alphanum? (string->list s))))
(define (alphanum? c)
(or (char-numeric? c)
(char-alphabetic? c)))
Related
Let's say I have a string s.
And this string s could contain this:
asdf-asdfasdfasf-fasdf-asdfasdfasdf
or this:
asf-asdfaf
but also this:
aasdaf
How do I count the number of dashes (-) in this string using Emacs Lisp and store this number in some variable e.g. count-of-dashes?
The following function should do it:
(defun count-chars (char str)
(let ((s (char-to-string char))
(count 0)
(start-pos -1))
(while (setq start-pos (string-search s str (+ 1 start-pos)))
(setq count (+ 1 count)))
count))
You call it like this:
(count-chars ?- "---") ==> 3
(count-chars ?- "foo-bar") ==> 1
(count-chars ?- "-foo-bar-baz") ==> 3
(count-chars ?- "foobarbaz") ==> 0
To set a variable to the number found, you just use
setq:
(setq count-of-chars (count-chars ?- "foo-bar-baz"))
Basically, we loop looking for the first dash: if we find it we remember where so that we start looking at the place just to the right of it the next time around the loop. The loop body then just counts every one we see. When we can't find any more, string-search (and the setq) returns nil and the loop exits, whereupon we return the accumulated count. See the doc string of the function string-search with C-h f string-search for the details.
Another method is more akin to the split string method of python: split-string splits a string on a separator into a list of parts. We then count the parts (the length of the list) and subtract 1: "a-b-c" is split into ("a" "b" "c") so there are three parts but only two separators.
(defun count-chars (char str)
(let ((s (char-to-string char)))
(- (length (split-string str s)) 1)))
Again, see the doc string of split-string (C-h f split-string) for all the details.
In both cases, we converted the character argument to a string argument, because both string-search in the first case and split-string in the second expect a string argument (to search for in the first case and to use as a separator in the second case - in fact, split-string can use a regular expression as a separator). Characters and strings are different data types in Emacs Lisp, so the conversion is necessary if you really want a character s the first argument of count-chars. But you could make it a string instead:
(defun count-seps (sep str)
(- (length (split-string str sep)) 1))
and then you would call it like this instead:
(count-seps "-" "abc-def-ghi-")
which is simpler and more general:
(count-seps "-;-" "abc-;-def") ==> 1
but you do have to worry about special characters in the separator string:
(count-seps "-*-" "abcd-------def") ==> 1
since the regular expression -*- matches one or more dashes so it matches all seven dashes: there is only one separator. Whether that's what you want is debatable. If you don't want it, you'd need to escape the special characters in the separator string:
(defun count-chars (sep str)
(let ((qsep (regexp-quote sep)))
(- (length (split-string str qsep)) 1)))
I am writing a function which can return the uppercase alphabets from an input string. And it works well when I display it. However, can anyone tell me how to return the output string rather than just display it?
(define (convert input)
(define s(string))
(for ([i (string->list input)])
(when (char-alphabetic? i)
(let ((s(string-append s (string i))))
(display (string-upcase s))))))
If you want to return data from a function, like you are here with returning a string, I suggest you look past the basic for loop to its variants, such as for/list, for/vector, for/hash, and for/fold. In this case for/list can help:
(define (convert input)
(list->string
(for/list ([i input] #:when (char-alphabetic? i))
(char-upcase i))))
Using it:
> (convert "ab1c23")
"ABC"
Here's one possible solution:
(define (convert input)
(list->string
(foldr (lambda (chr acc)
(if (char-alphabetic? chr)
(cons (char-upcase chr) acc)
acc))
'()
(string->list input))))
We need to accumulate the result somewhere, instead of printing char by char. For that, we use foldr to process a list of chars, uppercasing alphabetic chars and ignoring the others. This produces a list of chars that we convert back to a string using list->string. It works as expected:
(convert "ab1c23")
=> "ABC"
I have a loop with a condition, based on which I decide whether I should append something to existing string or not.
In Python, it should look like (this is dummy code, just to show the idea):
result_str = ''
for item in range(5):
if item % 2 == 0:
result_str += str(item)
print(result_str)
Output: 024
So the question is: how can I perform addition assignment on strings (+=) in lisp?
String concatenation relies on the more general CONCATENATE function:
(concatenate 'string "a" "b")
=> "ab"
Since it considered verbose by some, you can find libraries that implement shorter versions:
(ql:quickload :rutils)
(import 'rutils:strcat)
And then:
(strcat "a" "b")
In order to assign and grow a string, you need to use SETF with an existing variable.
(let ((string ""))
(dotimes (i 5)
(when (evenp i)
(setf string (strcat string (princ-to-string i)))))
string)
A more idiomatic way in Lisp is to avoid string concatenation, but print in a stream which writes into a buffer.
(with-output-to-string (stream)
;; now, stream is bound to an output stream
;; that writes into a string. The whole form
;; returns that string.
(loop
for i from 0 below 5 by 2
do (princ i stream)))
=> "024"
Here above, stream is just the symbol used for naming the stream, you could use any other one, including *standard-output*, the special variable that represents current output stream. Doing so would make the enclosed code redirect its standard output to the string stream.
An alternative way to build the intermediate list is the following, where iota is a small utility in the alexandria library:
(delete-if #'oddp (alexandria:iota 5))
=> (0 2 4)
In order to produce a string, you can also use FORMAT, which has a directive that can iterate over lists:
(format nil "~{~a~}" '(0 2 4))
=> "024"
The nil stream destination represents a string destination, meaning (format nil ...) returns a string. Each directive starts with a tilde character (~), ~{ and ~} enclose an iteration directive; inside that block, ~a prints the value "aesthetically" (not readably).
Lisp newbie here.
I want to read from standard-in a string of characters such as:
aabc
I want to convert that input into a list, where each character becomes a list element:
(a a b c)
And I want the list assigned to a global variable, text.
I created this function:
(defun get-line ()
(setf text (read)))
but that just results in assigning a single symbol to text, not tokenizing the input into a list of symbols.
What's the right way to implement get-line() please?
Here you go: First using coerce to convert the string to a list of characters, then mapcar to convert each character to a string.
(defun get-line ()
(setf text (mapcar 'string (coerce (string (read)) 'list))))
(loop
for x = (string-upcase (string (read-char)))
while (not (equal " " x))
collecting (intern x))
Note the upcase is there because symbols in CL are not case sensitive and are upcased by default by the reader.
How can I remove a certain character from a string in Nyquist (which is very similar to xlisp) and have the result returned?
I want to count how many "A" there are in a string like "ABBAAAABBBAABAAAB". (Yes, there are only 'A's and 'B's in the string.)
Since there is no (count) function in Nyquist I tried something like
(length (remove #\B mystring))
or
(length (remove #\B mystring :test equal))
But it doesn't work.
Forgetting the character count for a moment, how can I remove the 'B's from the string?
Will there always be only As and Bs in the string? If not, you might want to do something like
(remove #\A yourstring :test-not 'char=)
According to the XLISP reference for remove, the Nyquist remove doesn't deal with strings, only lists. You need to convert a string to a list in order to operate on it this way, but there's no coerce either. It's a touch hacky, but the easiest way around it I see is to stream a string and read-char it. This will produce a list of chars that you can then manipulate with remove.
(defun string->list (a-string)
(let ((collector nil)
(stream (make-string-input-stream a-string)))
(dotimes (c (length a-string) (reverse collector))
(setf collector (cons (read-char stream) collector)))))
It should now be possible to
(remove #\A (string->list yourstring) :test-not 'char=)
I see this is an old question, but since it has over 800 views, it's perhaps worth having the simple answer:
(defun remove-char (character sequence)
(let ((out ""))
(dotimes (i (length sequence) out)
(setf ch (char sequence i))
(unless (char= ch character)
(setf out (format nil "~a~a" out ch))))))
(setf mystring "ABBAABABCCCCBBCCCCAAA")
(remove-char #\B mystring) ;returns "AAAACCCCCCCCAAA"