How to convert list to string in Emacs Lisp - string

How can I convert a list to string so I can call insert or message with it? I need to display c-offsets-alist but I got Wrong type argument: char-or-string-p for insert or Wrong type argument: stringp for message.

I am not sure of what you are trying to achieve, but format converts "stuff" to strings. For instance:
(format "%s" your-list)
will return a representation of your list. message uses format internally, so
(message "%s" your-list)
will print it

(format) will embed parentheses in the string, e.g.:
ELISP> (format "%s" '("foo" "bar"))
"(foo bar)"
Thus if you need an analogue to Ruby/JavaScript-like join(), there is (mapconcat):
ELISP> (mapconcat 'identity '("foo" "bar") " ")
"foo bar"

Or
(prin1-to-string your-string)
Finally something special
(princ your-string)

M-x pp-eval-expression RET c-offsets-alist RET

If you need to convert a list like ((a b c d e)) to a string "a b c d e" then this function might help:
(defun convert-list-to-string (list)
"Convert LIST to string."
(let* ((string-with-parenthesis (format "%S" list))
(end (- (length string-with-parenthesis) 2)))
(substring string-with-parenthesis 2 end)))

Related

Replacing characters in a string, with a set of characters inside of a map in Clojure

I have a function that takes in a string s and a map of characters charmap. If any characters in the string s are inside of charmap, replace the character with the value of the map.
Note, the keys in the map must be a string, rather than a char.
For example:
(replace-characters "Hi!" {"!" "Exclamation Mark"}) ;; => "HiExclamation Mark"
This is the code I am currently using:
(defn- replace-characters
"Replaces any characters in a string that are mapped in the given charmap"
[s charmap]
(let [character-set (set s)
characters (filter #(contains? charmap (str %)) character-set)]
(string/replace s (re-pattern (string/join "|" characters)) charmap)))
However, I am getting a NullPointerException and I am seriously confused on why.
java.lang.NullPointerException: Cannot invoke "String.indexOf(int)" because "s" is null
I would like to solve this in pure Clojure preferably, not Java, etc.
Update: So the code above works in the repl. Which is nice. But for some reason the following is causing the error:
(-> s
(string/replace #"[:/?#\[\]#!$&'()*+,;=]" "")
(replace-characters charmap)) ;; Where charmap is a large map of key value characters.
This is the expression that causes error:
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
("!" was replaced with regex to "", character-set has value #{\H \i} and characters is (), so pattern created with re-pattern is #"".)
Empty regex matches every space between letters:
(str/replace "Hi" #"" " ")
=> " H i "
So, replace is looking for replacement in hash-map {"!" "Exclamation Mark"}, but doesn't find anything- there is no key "":
(str/replace "Hi" #"" {"!" "Exclamation Mark"})
=> error
(str/replace "Hi" #"" {"" " "})
=> " H i "
One possible solution can be to simplify definition of replace-characters (this solution will work only for non-empty charmap):
(defn replace-characters [s charmap]
(str/replace s (re-pattern (str/join "|" (keys charmap)))
charmap))
Tests:
(replace-characters "Hi!" {"!" "Exclamation Mark"})
=> "HiExclamation Mark"
(-> "Hi!"
(str/replace #"[:/?#\[\]#!$&'()*+,;=]" "")
(replace-characters {"!" "Exclamation Mark"}))
=> "Hi"
i would just go with something as simple as this:
(apply str (replace {"!" "[exclamation mark]"
"?" "[question mark]"}
(map str "is it possible? sure!")))
;;=> "is it possible[question mark] sure[exclamation mark]"
or this way with transducers:
(apply str (eduction (map str) (replace {"!" "[exclamation mark]"
"?" "[question mark]"})
"is it possible? sure!"))
or maybe like this:
(defn replace-characters [s rep]
(apply str (map #(rep (str %) %) s)))
user> (replace-characters "is it possible? sure!" {"!" "[exclamation mark]"
"?" "[question mark]"})
;;=> "is it possible[question mark] sure[exclamation mark]"
string/escape does exactly what you want:
(string/escape "Hi!" {\! "Exclamation Mark"})
;; => "HiExclamation Mark"
that function replaces characters using a map from character to replacement.
If you want to replace regexes or string you can use reduce-kv in combination with string/replace:
(def replacements
(array-map
"!" "Exclamation Mark"
#"[:/?#\[\]#!$&'()*+,;=]" ""
#_more_replacements))
(defn replace [s replacements]
(reduce-kv string/replace s replacements))
So you loop (in order, when replacements is an array-map) over the key and values of the replacements and apply them on the string s using string/replace.
(replace "Hi!" replacements)
;; => "HiExclamation Mark"
if the order of the elements in the array-map is reversed the substitution of the ! with "" (since ! is in the regex) would succeed:
(replace "Hi!" (into (array-map) (reverse replacements)))
;; => "Hi"

How to distinguish escaped characters from non-escaped e.g. "\x27" from "x27" in a string in Common Lisp?

Solving Advent of Code 2015 task 8 part2 I encountered the problem to have to distinguish in a string the occurrence of "\x27" from plain "x27".
But I don't see a way how I can do it. Because
(length "\x27") ;; is 3
(length "x27") ;; is also 3
(subseq "\x27" 0 1) ;; is "x"
(subseq "x27" 0 1) ;; is "x"
Neither print, prin1, princ made a difference.
# nor does `coerce`
(coerce "\x27" 'list)
;; (#\x #\2 #\7)
So how then to distinguish in a string when "\x27" or any of such
hexadecimal representation occurs?
It turned out, one doesn't need to solve this to solve the task. However, now I still would like to know whether there is a way to distinguish "\x" from "x" in common lisp.
The string literal "\x27" is read as the same as "x27", because \ is an escape character in string literals. If you want a string with the contents \x27, you need to write the literal as "\\x27" (i. e. escape the escape character). This has nothing to do with the strings themselves. If you read a string from a file containing \x27 (e. g. with read-line), then the four-character string \x27 results.
By the time that the Lisp reader gets to work, \x is the same as x. There may be some way to turn this off - I wouldn't be surprised - but the original text talks about Santa's file.
So, I created my own file, like this:
x27
\x27
And I read the data into special variables like this:
(defun read-line-crlf (stream)
(string-right-trim '(#\Return) (read-line stream nil)))
(defun read-lines (filename)
(with-open-file (stream filename)
(setf x (read-line-crlf stream))
(setf x-esc (read-line-crlf stream))
))
The length of x is then 3, and the length of x-esc is 4. The returned string must be trimmed on Windows, or an external format declared, because otherwise SBCL will leave half of the CR-LF on the end of the read strings.

Convert string to title case - Emacs Lisp

I am looking for an elisp function that accepts a string and returns the same in title case (i.e., all words capitalized, except for "a", "an", "on", "the", etc.).
I found this script, which requires a marked region.
Only, I need a function that accepts a string variable, so I can use it with replace-regex. I would love to see a version of the above script that can accept either or...
Something like this?
(progn
(defun title-case (input) ""
(let* (
(words (split-string input))
(first (pop words))
(last (car(last words)))
(do-not-capitalize '("the" "of" "from" "and" "yet"))) ; etc
(concat (capitalize first)
" "
(mapconcat (lambda (w)
(if (not(member (downcase w) do-not-capitalize))
(capitalize w)(downcase w)))
(butlast words) " ")
" " (capitalize last))))
(title-case "the presentation of this HEADING OF my own from my keyboard and yet\n"))
I'd say that the script you linked to does a good job at title casing. You can use it as-is.
That leaves us with two more questions:
How can we make it accept a string?
How can we write a function which accepts both a string or a (marked) region?
Working with strings in Emacs is idiomatically done in temporary buffers which are not displayed. You could write a wrapper like this:
(defun title-capitalization-string (s)
(with-temp-buffer
(erase-buffer)
(insert s)
(title-capitalization (point-min)
(point-max))
(buffer-substring-no-properties (point-min)
(point-max))))
Now, for a function which magically does what you mean, consider something like this:
(defun title-capitalization-dwim (&optional arg)
(interactive)
(cond
(arg
(title-capitalization-string arg))
((use-region-p)
(title-capitalization-string
(buffer-substring-no-properties (region-beginning)
(region-end))))
(t
(title-capitalization-string
(buffer-substring-no-properties (point-at-bol)
(point-at-eol))))))
It accepts an optional argument, or an active region or falls back to the text on the current line. Note that this function is not really useful when used interactively, because it doesn't show any effects. Hat tip also to https://www.emacswiki.org/emacs/titlecase.el
License
I put all this code under the Apache License 2.0 and the GPL 2.0 (or later at your option) in addition to the site's default license.
Use M-x
upcase-initials-region is an interactive built-in function in ‘C
source code’.
(upcase-initials-region BEG END)
Upcase the initial of each word in the region. This means that each
word’s first character is converted to either title case or upper
case, and the rest are left unchanged. In programs, give two
arguments, the starting and ending character positions to operate on.

what is the interactive REPL IO function?

I have been learning Common Lisp for a while, there was a question I have met that
how I can implement such a function which allows user to input some words until user input exit.
(actually I want to know what kind of command line interactive function APIs fit such requirement)
e.g.
prompt "please input a word: " in the REPL, then store user inputs into a global my-words , exit when user input "exit".
You specification is a little bit incomplete (e.g. what constitutes a word in your problem? What if the user add multiple words? What if the input is empty?). Here below I am using CL-PPCRE to split the input into different words and add them all at once, because it seems useful in general. In your case you might want to add more error checking.
If you want to interact with the user, you should read and write from and to the *QUERY-IO* stream. Here I'll present a version with a global variables, as you requested, as well as another one without side-effects (apart from input/output).
With a global variable
Define the global variable and initialize it with an empty adjustable array.
I am using an array so that it is easy to add words at the end, but you could also use a queue.
(defvar *my-words* (make-array 10 :fill-pointer 0 :adjustable t))
The following function mutates the global variable:
(defun side-effect-word-repl ()
(loop
(format *query-io* "~&Please input a word: ")
(finish-output *query-io*)
(let ((words (ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
(read-line *query-io*))))
(dolist (w words)
(when (string-equal w "exit") ; ignore case
(return-from side-effect-word-repl))
(vector-push-extend w *my-words*)))))
The LOOP uses the simple syntax where there are only expressions and no loop-specific keywords. I first write the prompt to *QUERY-IO*. The ~& FORMAT directive performs the same operation as FRESH-LINE. As Rainer pointed out in comments, we have to call FINISH-OUTPUT to ensure the message is effectively printed before the user is expected to reply.
Then, I read a whole line from the same bidirectional stream, and split it into a list of words, where a word is a string of non-whitespace characters.
With DOLIST, I iterate over the list and add words into the global array with VECTOR-PUSH-EXTEND. But as soon as I encouter "exit", I terminate the loop; since I rely on STRING-EQUAL, the test is done case-insensitively.
Side-effect free approach
Having a global variable as done above is discouraged. If you only need to have a prompt which returns a list of words, then the following will be enough. Here, I use the PUSH/NREVERSE idiom to built the resulting list of words.
(defun pure-word-repl ()
(let ((result '()))
(loop
(format *query-io* "~&Please input a word: ")
(finish-output *query-io*)
(let ((words (ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
(read-line *query-io*))))
(dolist (w words)
(when (string-equal w "exit")
(return-from pure-word-repl (nreverse result)))
(push w result))))))
Note about words
As jkiiski commented, it might be better to split words at :word-boundary. I tried different combinations and the following result seems satisfying with weird example strings:
(mapcan (lambda (string)
(ppcre:split :word-boundary string))
(ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
"amzldk 'amlzkd d;:azdl azdlk"))
=> ("amzldk" "'" "amlzkd" "d" ";:" "azdl" "azdlk")
I first remove all whitespaces and split the string into a list of strings, which can contain punctuation marks. Then, each string is itself splitted at :word-boundary, and concatenated with MAPCAN to form a list of separate words. However, I can't really guess what your actual needs are, so you should probably define your own SPLIT-INTO-WORDS function to validate and split an input string.
CL-USER 23 > (progn
(format t "~%enter a list of words:~%")
(finish-output)
(setf my-words (read))
(terpri))
enter a list of words:
(foo bar baz)
or
CL-USER 28 > (loop with word = nil
do
(format t "~%enter a word or exit:~%")
(finish-output)
(setf word (read))
(terpri)
until (eql word 'exit)
collect word)
enter a word or exit:
foo
enter a word or exit:
bar
enter a word or exit:
baz
enter a word or exit:
exit
(FOO BAR BAZ)

Sorting a string alphabetically by line in Clojure(Script)

Suppose S is a string defined as follows:
;; S
B
C
A
Is there some clojure operation sort-alphabetically (that also works in clojurescript) such that (sort-alphabetically S) generates the following string?
;; (sort-alphabetically S) =>
A
B
C
The following code snippet will do what you want:
(require '[clojure.string :as str])
(def s "C\nB\nA")
(->> s
(str/split-lines) ; split your string into sequence of lines
(sort) ; sort the sequence using natural order (for strings it will be alphabetical order)
(str/join "\n")) ; join elements of the sorted sequence using \n producing a multiline string
;; => "A\nB\nC"
I think you want:
(def foo "a\ne\nc")
(:use clojure.string)
(sort (clojure.string/split foo #"\n"))
;; ("a" "c" "e")
In general you should try to provide a definition of the data that is executable or at least enclosed in parens to make it clear exactly what the data looks like, per the advice of #jmargolisvt

Resources