How to center a string in elisp? - string

I would like to center justify a given input string to a given size so that what is produced is a string with padded spaces either side (left and right) of the input string.
The code I have to do this:
(defun center-string (string size)
(let* ((padding (/ (- size (length string)) 2))
(lpad (+ (length string) padding))
(lformat (format "%%%ds" lpad))
(rformat (format "%%%ds" (- size))))
(format rformat (format lformat string))))
And some test cases:
(center-string "KJF" 10)
=> " KJF "
(center-string "KF" 10)
=> " KF "
(center-string "0123456789" 10)
=> "0123456789"
(center-string "0123456789" 5)
=> "0123456789" ; Notice justifcation is ignored as input string too large.
Is there an existing elisp function to do this or a better method?

There's a center-line, which works in a buffer (and uses the buffer's value of fill-column as the line length), so if your goal is to produce a nicely formatted file, you could do something like
(defun insert-centered (x)
(insert "\n" x)
(center-line)
(insert "\n"))

No, there is not an existing emacs lisp routine that does what you want. (the standard search through emacs lisp info and emacs info supports this).

Related

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.

Scheme string-ref and char-whitespace? using

(define len (string-length "James ApR23Trb&%25G)(=?vqa"))
(define (divide-string str)
(let (x)
(if (char-whitespace? (string-ref str x))
(substring str (+ 1 x) (- len 1))
(printf "an invalid input!"))
))
(divide-string "James ApR23Trb&%25G)(=?vqa")
I have a string with divided into a blank space. I need to handle two
substring. One is till blank space and the other one is from blank
space. But i could not handle the index of blank space with x.
Any help will be appraciated. Thank you even now.
Try regexp-split:
> (regexp-split #rx"\\s" "James ApR23Trb&%25G)(=?vqa")
'("Jame" " ApR23Trb&%25G)(=?vqa")
Here \\s matches whitespace.
Oops. I mistook the question for a Racket question.
In a Scheme implementation: search for split in the documentation
and see what your implementation of choice has available.

How to convert list to string in Emacs Lisp

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)))

Appending character to string in Common Lisp

I have a character ch that I want to append to a string str. I realize you can concatenate strings like such:
(setf str (concatenate 'string str (list ch)))
But that seems rather inefficient. Is there a faster way to just append a single character?
If the string has a fill-pointer and maybe is also adjustable.
Adjustable = can change its size.
fill-pointer = the content size, the length, can be less than the string size.
VECTOR-PUSH = add an element at the end and increment the fill-pointer.
VECTOR-PUSH-EXTEND = as VECTOR-PUSH, additionally resizes the array, if it is too small.
We can make an adjustable string from a normal one:
CL-USER 32 > (defun make-adjustable-string (s)
(make-array (length s)
:fill-pointer (length s)
:adjustable t
:initial-contents s
:element-type (array-element-type s)))
MAKE-ADJUSTABLE-STRING
CL-USER 33 > (let ((s (make-adjustable-string "Lisp")))
(vector-push-extend #\! s)
s)
"Lisp!"
If you want to extend a single string multiple times, it is often
quite performant to use with-output-to-string, writing to the stream
it provides. Be sure to use write or princ etc. (instead of format)
for performance.

Make String from Sequence of Characters

This code does not work as I expected. Could you please explain why?
(defn make-str [s c]
(let [my-str (ref s)]
(dosync (alter my-str str c))))
(defn make-str-from-chars
"make a string from a sequence of characters"
([chars] make-str-from-chars chars "")
([chars result]
(if (== (count chars) 0) result
(recur (drop 1 chars) (make-str result (take 1 chars))))))
Thank you!
This is very slow & incorrect way to create string from seq of characters. The main problem, that changes aren't propagated - ref creates new reference to existing string, but after it exits from function, reference is destroyed.
The correct way to do this is:
(apply str seq)
for example,
user=> (apply str [\1 \2 \3 \4])
"1234"
If you want to make it more effective, then you can use Java's StringBuilder to collect all data in string. (Strings in Java are also immutable)
You pass a sequence with one character in it to your make-str function, not the character itself. Using first instead of take should give you the desired effect.
Also there is no need to use references. In effect your use of them is a gross misuse of them. You already use an accumulator in your function, so you can use str directly.
(defn make-str-from-chars
"make a string from a sequence of characters"
([chars] (make-str-from-chars chars ""))
([chars result]
(if (zero? (count chars))
result
(recur (drop 1 chars) (str result (first chars))))))
Of course count is not very nice in this case, because it always has to walk the whole sequence to figure out its length. So you traverse the input sequence several times unnecessarily. One normally uses seq to identify when a sequence is exhausted. We can also use next instead of drop to save some overhead of creating unnecessary sequence objects. Be sure to capture the return value of seq to avoid overhead of object creations later on. We do this in the if-let.
(defn make-str-from-chars
"make a string from a sequence of characters"
([chars] (make-str-from-chars chars ""))
([chars result]
(if-let [chars (seq chars)]
(recur (next chars) (str result (first chars)))
result)))
Functions like this, which just return the accumulator upon fully consuming its input, cry for reduce.
(defn make-str-from-chars
"make a string from a sequence of characters"
[chars]
(reduce str "" chars))
This is already nice and short, but in this particular case we can do even a little better by using apply. Then str can use the underlying StringBuilder to its full power.
(defn make-str-from-chars
"make a string from a sequence of characters"
[chars]
(apply str chars))
Hope this helps.
You can also use clojure.string/join, as follows:
(require '[clojure.string :as str] )
(assert (= (vec "abcd") [\a \b \c \d] ))
(assert (= (str/join (vec "abcd")) "abcd" ))
There is an alternate form of clojure.string/join which accepts a separator. See:
http://clojuredocs.org/clojure_core/clojure.string/join

Resources