S.el
The long lost Emacs string manipulation library.
Install / Use
/learn @magnars/S.elREADME
s.el

The long lost Emacs string manipulation library.
Installation
It's available on Melpa:
M-x package-install s
Or you can just dump s.el in your load path somewhere.
Functions
Tweak whitespace
- s-trim
(s) - s-trim-left
(s) - s-trim-right
(s) - s-chomp
(s) - s-collapse-whitespace
(s) - s-word-wrap
(len s) - s-center
(len s) - s-pad-left
(len padding s) - s-pad-right
(len padding s)
To shorter string
- s-truncate
(len s) - s-left
(len s) - s-right
(len s) - s-chop-left
(len s) - s-chop-right
(len s) - s-chop-suffix
(suffix s) - s-chop-suffixes
(suffixes s) - s-chop-prefix
(prefix s) - s-chop-prefixes
(prefixes s) - s-shared-start
(s1 s2) - s-shared-end
(s1 s2)
To longer string
- s-repeat
(num s) - s-concat
(&rest strings) - s-prepend
(prefix s) - s-append
(suffix s) - s-splice
(needle n s)
To and from lists
- s-lines
(s) - s-match
(regexp s &optional start) - s-match-strings-all
(regex string) - s-matched-positions-all
(regexp string &optional subexp-depth) - s-slice-at
(regexp s) - s-split
(separator s &optional omit-nulls) - s-split-up-to
(separator s n &optional omit-nulls) - s-join
(separator strings)
Predicates
- s-equals?
(s1 s2) - s-less?
(s1 s2) - s-matches?
(regexp s &optional start) - s-blank?
(s) - s-present?
(s) - s-ends-with?
(suffix s &optional ignore-case) - s-starts-with?
(prefix s &optional ignore-case) - s-contains?
(needle s &optional ignore-case) - s-lowercase?
(s) - s-uppercase?
(s) - s-mixedcase?
(s) - s-capitalized?
(s) - s-numeric?
(s)
The misc bucket
- s-replace
(old new s) - s-replace-all
(replacements s) - s-downcase
(s) - s-upcase
(s) - s-capitalize
(s) - s-titleize
(s) - s-with
(s form &rest more) - s-index-of
(needle s &optional ignore-case) - s-reverse
(s) - s-presence
(s) - s-format
(template replacer &optional extra) - s-lex-format
(format-str) - s-count-matches
(regexp s &optional start end) - s-wrap
(s prefix &optional suffix)
Pertaining to words
- s-split-words
(s) - s-lower-camel-case
(s) - s-upper-camel-case
(s) - s-snake-case
(s) - s-dashed-words
(s) - s-capitalized-words
(s) - s-titleized-words
(s) - s-word-initials
(s) - s-blank-str?
(s)
Documentation and examples
s-trim (s)
Remove whitespace at the beginning and end of s.
(s-trim "trim ") ;; => "trim"
(s-trim " this") ;; => "this"
(s-trim " only trims beg and end ") ;; => "only trims beg and end"
s-trim-left (s)
Remove whitespace at the beginning of s.
(s-trim-left "trim ") ;; => "trim "
(s-trim-left " this") ;; => "this"
s-trim-right (s)
Remove whitespace at the end of s.
(s-trim-right "trim ") ;; => "trim"
(s-trim-right " this") ;; => " this"
s-chomp (s)
Remove one trailing \n, \r or \r\n from s.
(s-chomp "no newlines\n") ;; => "no newlines"
(s-chomp "no newlines\r\n") ;; => "no newlines"
(s-chomp "some newlines\n\n") ;; => "some newlines\n"
s-collapse-whitespace (s)
Convert all adjacent whitespace characters to a single space.
(s-collapse-whitespace "only one space please") ;; => "only one space please"
(s-collapse-whitespace "collapse \n all \t sorts of \r whitespace") ;; => "collapse all sorts of whitespace"
s-word-wrap (len s)
If s is longer than len, wrap the words with newlines.
(s-word-wrap 10 "This is too long") ;; => "This is\ntoo long"
(s-word-wrap 10 "This is way way too long") ;; => "This is\nway way\ntoo long"
(s-word-wrap 10 "It-wraps-words-but-does-not-break-them") ;; => "It-wraps-words-but-does-not-break-them"
s-center (len s)
If s is shorter than len, pad it with spaces so it is centered.
(s-center 5 "a") ;; => " a "
(s-center 5 "ab") ;; => " ab "
(s-center 1 "abc") ;; => "abc"
s-pad-left (len padding s)
If s is shorter than len, pad it with padding on the left.
(s-pad-left 3 "0" "3") ;; => "003"
(s-pad-left 3 "0" "23") ;; => "023"
(s-pad-left 3 "0" "1234") ;; => "1234"
s-pad-right (len padding s)
If s is shorter than len, pad it with padding on the right.
(s-pad-right 3 "." "3") ;; => "3.."
(s-pad-right 3 "." "23") ;; => "23."
(s-pad-right 3 "." "1234") ;; => "1234"
s-truncate (len s)
If s is longer than len, cut it down to len - 3 and add ... at the end.
(s-truncate 6 "This is too long") ;; => "Thi..."
(s-truncate 16 "This is also too long") ;; => "This is also ..."
(s-truncate 16 "But this is not!") ;; => "But this is not!"
s-left (len s)
Returns up to the len first chars of s.
(s-left 3 "lib/file.js") ;; => "lib"
(s-left 3 "li") ;; => "li"
s-right (len s)
Returns up to the len last chars of s.
(s-right 3 "lib/file.js") ;; => ".js"
(s-right 3 "li") ;; => "li"
s-chop-left (len s)
Remove the first len chars from s.
(s-chop-left 3 "lib/file.js") ;; => "/file.js"
(s-chop-left 3 "li") ;; => ""
s-chop-right (len s)
Remove the last len chars from s.
(s-chop-right 3 "lib/file.js") ;; => "lib/file"
(s-chop-right 3 "li") ;; => ""
s-chop-suffix (suffix s)
Remove suffix if it is at end of s.
(s-chop-suffix "-test.js" "penguin-test.js") ;; => "penguin"
(s-chop-suffix "\n" "no newlines\n") ;; => "no newlines"
(s-chop-suffix "\n" "some newlines\n\n") ;; => "some newlines\n"
s-chop-suffixes (suffixes s)
Remove suffixes one by one in order, if they are at the end of s.
(s-chop-suffixes '("_test.js" "-test.js" "Test.js") "penguin-test.js") ;; => "penguin"
(s-chop-suffixes '("\r" "\n") "penguin\r\n") ;; => "penguin\r"
(s-chop-suffixes '("\n" "\r") "penguin\r\n") ;; => "penguin"
s-chop-prefix (prefix s)
Remove prefix if it is at the start of s.
(s-chop-prefix "/tmp" "/tmp/file.js") ;; => "/file.js"
(s-chop-prefix "/tmp" "/tmp/tmp/file.js") ;; => "/tmp/file.js"
s-chop-prefixes (prefixes s)
Remove prefixes one by one in order, if they are at the start of s.
(s-chop-prefixes '("/tmp" "/my") "/tmp/my/file.js") ;; => "/file.js"
(s-chop-prefixes '("/my" "/tmp") "/tmp/my/file.js") ;; => "/my/file.js"
s-shared-start (s1 s2)
Returns the longest prefix s1 and s2 have in common.
(s-shared-start "bar" "baz") ;; => "ba"
(s-shared-start "foobar" "foo") ;; => "foo"
(s-shared-start "bar" "foo") ;; => ""
s-shared-end (s1 s2)
Returns the longest suffix s1 and s2 have in common.
(s-shared-end "bar" "var") ;; => "ar"
(s-shared-end "foo" "foo") ;; => "foo"
(s-shared-end "bar" "foo") ;; => ""
s-repeat (num s)
Make a string of s repeated num times.
(s-repeat 10 " ") ;; => " "
(s-concat (s-repeat 8 "Na") " Batman!") ;; => "NaNaNaNaNaNaNaNa Batman!"
s-concat (&rest strings)
Join all the string arguments into one string.
(s-concat "abc" "def" "ghi") ;; => "abcdefghi"
s-prepend (prefix s)
Concatenate prefix and s.
(s-prepend "abc" "def") ;; => "abcdef"
s-append (suffix s)
Concatenate s and suffix.
(s-append "abc" "def") ;; => "defabc"
s-splice (needle n s)
Splice needle into s at position n.
0 is the beginning of the string, -1 is the end.
(s-splice "abc" 0 "def") ;; => "abcdef"
(s-splice "abc" -1 "def") ;; => "defabc"
(s-splice "needle" 2 "A in a haystack.") ;; => "A needle in a haystack."
s-lines (s)
Splits s into a list of strings on newline characters.
(s-lines "abc\ndef\nghi") ;; => '("abc" "def" "ghi")
(s-lines "abc\rdef\rghi") ;; => '("abc" "def" "ghi")
(s-lines "abc\r\ndef\r\nghi") ;; => '("abc" "def" "ghi")
s-match (regexp s &optional start)
When the given ex
Related Skills
node-connect
346.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
107.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
346.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
346.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
