Ruby
Emacs
string
emacs-lisp
s.el

Emacs用文字列操作ライブラリ s.el の使い方

More than 1 year has passed since last update.

Emacs用文字列操作ライブラリ s.el の使い方の練習です。
自分用およびRuby脳な人にもわかりやすいように Ruby だとどんな感じになるかも合わせて書いています。

左スペース除去 (s-trim-left)

EmacsLisp
(s-trim-left " a ")    ; => "a "
Ruby
" a ".lstrip    # => "a "

右スペース除去 (s-trim-right)

EmacsLisp
(s-trim-right " a ")    ; => " a"
Ruby
" a ".rstrip    # => " a"

左右スペース除去 (s-trim)

EmacsLisp
(s-trim " a ")    ; => "a"
Ruby
" a ".strip    # => "a"

2つ以上のスペースを1つに置換 (s-collapse-whitespace)

EmacsLisp
(s-collapse-whitespace "  a  b  c  ")    ; => " a b c "
Ruby
"  a  b  c  ".squeeze(" ")    # => " a b c "

区切り文字で分割 (s-split)

EmacsLisp
(s-split "," "a,b,c")    ; => ("a" "b" "c")
Ruby
"a,b,c".split(/,/)    # => ["a", "b", "c"]

区切り文字でN個だけ分割 (s-split-up-to)

EmacsLisp
(s-split-up-to "," "a,b,c" 1)    ; => ("a" "b,c")
Ruby
"a,b,c".split(/,/, 2)    # => ["a", "b,c"]

行毎に分割 (s-lines)

EmacsLisp
(s-lines "a\nb\nc")    ; => ("a" "b" "c")
Ruby
"a\nb\nc".split(/\n/)    # => ["a", "b", "c"]

区切り文字を間に入れて結合 (s-join)

EmacsLisp
(s-join "," '("a" "b" "c"))    ; => "a,b,c"
Ruby
["a", "b", "c"].join(",")    # => "a,b,c"

文字列の結合 (s-concat)

EmacsLisp
(s-concat "a" "b" "c")    ; => "abc"
Ruby
"a" "b" "c"    # => "abc"

前に結合 (s-prepend)

EmacsLisp
(s-prepend "_" "foo")    ; => "_foo"
Ruby
"_" + "foo"    # => "_foo"

後ろに結合 (s-append)

EmacsLisp
(s-append "_" "foo")    ; => "foo_"
Ruby
"foo" + "_"    # => "foo_"

文字列の繰り返し (s-repeat)

EmacsLisp
(s-repeat 3 "a")    ; => "aaa"
Ruby
"a" * 3    # => "aaa"

プレフィクス除去 (s-chop-prefix)

EmacsLisp
(s-chop-prefix "a" "ax")    ; => "x"
Ruby
"ax".sub(/\Aa/, "")    # => "x"

複数のプレフィクス除去 (s-chop-prefixes)

EmacsLisp
(s-chop-prefixes '("a" "b") "abx")    ; => "x"
Ruby
["a", "b"].inject("abx") { |a, e| a.sub(/\A#{e}/, "") }    # => "x"

サフィックス除去 (s-chop-suffix)

EmacsLisp
(s-chop-suffix "a" "xa")    ; => "x"
Ruby
"xa".sub(/a\z/, "")    # => "x"

複数のサフィックス除去 (s-chop-suffixes)

EmacsLisp
(s-chop-suffixes '("a" "b") "xba")    ; => "x"
Ruby
["a", "b"].inject("xba") { |a, e| a.sub(/#{e}\z/, "") }    # => "x"

共通のプレフィクスを抽出 (s-shared-start)

EmacsLisp
(s-shared-start "axb" "ayb")    ; => "a"
Ruby
a = "axb"
b = "ayb"
it = b.each_char
i = a.chars.find_index { |e| e != it.next }
i ? a[0...i] : ""    # => "a"

共通のサフィックスを抽出 (s-shared-end)

EmacsLisp
(s-shared-end "axb" "ayb")    ; => "b"
Ruby
a = "axb"
b = "ayb"
it = b.chars.reverse.each
i = a.chars.reverse.find_index { |e| e != it.next }
i ? a.chars.last(i).join : ""    # => "b"

行末の改行除去 (s-chomp)

EmacsLisp
(s-chomp "a\r\n")    ; => "a"
Ruby
"a\r\n".chomp    # => "a"

ちょんぎる (s-truncate)

EmacsLisp
(s-truncate 5 "0123456789")    ; => "01..."
ActiveSupport
"0123456789".truncate(5)    # => "01..."

指定横幅に収まるように整形 (s-word-wrap)

EmacsLisp
(s-word-wrap 4 "a b c")    ; => "a b\nc"
Ruby
require "nkf"
NKF.nkf("-f#{4.pred} -w", "a b c").rstrip    # => "a b\nc"

# マルチバイト未対応だけど
require "action_view"
include ActionView::Helpers::TextHelper
word_wrap("a b c", line_width: 4)    # => "a b\nc"

中央寄せ (s-center)

EmacsLisp
(s-center 5 "a")    ; => "  a  "
Ruby
"a".center(5)    # => "  a  "

左寄せ (s-pad-right)

EmacsLisp
(s-pad-right 5 " " "a")    ; => "a    "
Ruby
"a".ljust(5)    # => "a    "

右寄せ (s-pad-left)

EmacsLisp
(s-pad-left 5 " " "a")    ; => "    a"
Ruby
"a".rjust(5)    # => "    a"

先頭N文字 (s-left)

EmacsLisp
(s-left 2 "012")    ; => "01"
Ruby
"012"[0...2]    # => "01"

後ろのN文字 (s-right)

EmacsLisp
(s-right 2 "012")    ; => "12"
Ruby
"012"[-2..-1]    # => "12"

サフィックス確認 (s-ends-with?)

EmacsLisp
(s-ends-with? "c" "abc")    ; => t
Ruby
"abc".end_with?("c")    # => true

プレフィクス確認 (s-starts-with?)

EmacsLisp
(s-starts-with? "a" "abc")    ; => t
Ruby
"abc".start_with?("a")    # => true

文字列が含まれる? (s-contains?)

EmacsLisp
(s-contains? "b" "abc")    ; => t
Ruby
"abc".include?("b")    # => true

文字列が一致する? (s-equals?)

EmacsLisp
(s-equals? "a" "a")    ; => t
Ruby
"a" == "a"    # => true

文字列をコードの大小で比較 (s-less?)

EmacsLisp
(s-less? "a" "b")    ; => t
Ruby
"a" < "b"    # => true

正規表現がマッチする? (s-matches?)

EmacsLisp
(s-matches? "\\w+" "foo")    ; => t
Ruby
"foo".match?(/\w+/)    # => true

なんもない? (s-blank?)

EmacsLisp
(s-blank? "")    ; => t
ActiveSupport
"".blank?    # => true

なんかある? (s-present?)

EmacsLisp
(s-present? "x")    ; => t
ActiveSupport
"x".present?    # => true

なんかあればそれ (s-presence)

EmacsLisp
(s-presence "x")    ; => "x"
ActiveSupport
"x".presence    # => "x"

全部小文字? (s-lowercase?)

EmacsLisp
(s-lowercase? "foo")    ; => t
Ruby
"foo".match?(/\A[[:lower:]]*\z/)    # => true

全部大文字? (s-uppercase?)

EmacsLisp
(s-uppercase? "FOO")    ; => t
Ruby
"FOO".match?(/\A[[:upper:]]*\z/)    # => true

大文字と小文字の両方含まれる? (s-mixedcase?)

EmacsLisp
(s-mixedcase? "aBc")    ; => t
Ruby
str = "aBc"    # => "aBc"
str.match?(/[[:upper:]]/) && str.match?(/[[:lower:]]/)    # => true

最初だけ大文字? (s-capitalized?)

EmacsLisp
(s-capitalized? "Foo")    ; => t
Ruby
"Foo".match?(/\A[[:upper:]][[:lower:]]/)    # => true

全部数文字? (s-numeric?)

EmacsLisp
(s-numeric? "123")    ; => t
Ruby
"123".match?(/\A\d+\z/)    # => true

文字列置換 (s-replace)

EmacsLisp
(s-replace "a" "x" "abab")    ; => "xbxb"
Ruby
"abab".gsub(/a/, "x")    # => "xbxb"

複数指定できる文字列置換 (s-replace-all)

EmacsLisp
(s-replace-all '(("a" . "x") ("b" . "y")) "abab")    ; => "xyxy"
Ruby
{"a" => "x", "b" => "y"}.inject("abab") { |s, (a, b)| s.gsub(a, b) }    # => "xyxy"

小文字にする (s-downcase)

EmacsLisp
(s-downcase "Foo")    ; => "foo"
Ruby
"Foo".downcase    # => "foo"

大文字にする (s-upcase)

EmacsLisp
(s-upcase "Foo")    ; => "FOO"
Ruby
"Foo".upcase    # => "FOO"

先頭だけ大文字にする (s-capitalize)

EmacsLisp
(s-capitalize "foo_bar")    ; => "Foo_bar"
Ruby
"foo_bar".capitalize    # => "Foo_bar"

単語の先頭を大文字にする (s-titleize)

EmacsLisp
(s-titleize "foo bar")    ; => "Foo Bar"
ActiveSupport
"foo bar".titleize    # => "Foo Bar"

複数の関数を適用 (s-with)

EmacsLisp
(s-with "abc" s-upcase s-reverse)    ; => "CBA"
Ruby
[:upcase, :reverse].reduce("abc", &:send)    # => "CBA"

文字列内の位置を返す (s-index-of)

EmacsLisp
(s-index-of "bc" "abcd")    ; => 1
Ruby
"abcd".index("bc")    # => 1

反転 (s-reverse)

EmacsLisp
(s-reverse "abc")    ; => "cba"
Ruby
"abc".reverse    # => "cba"

複数のマッチした部分を返す (s-match-strings-all)

EmacsLisp
(s-match-strings-all "\\w\\(\\w\\)" "a1 a2")    ; => (("a1" "1") ("a2" "2"))
Ruby
"a1 a2".scan(/(\w(\w+))/)    # => [["a1", "1"], ["a2", "2"]]

マッチした部分を返す (s-match)

EmacsLisp
(s-match "\\w\\(\\w+\\)" "a1 a2")    ; => ("a1" "1")
Ruby
"a1 a2".match(/\w(\w+)/).to_a    # => ["a1", "1"]

マッチした部分の前で分離 (s-slice-at)

EmacsLisp
(s-slice-at "a" "a1a2a3")    ; => ("a1" "a2" "a3")
Ruby
"a1a2a3".split(/(?=a)/)    # => ["a1", "a2", "a3"]

単語っぽいのを拾う (s-split-words)

EmacsLisp
; どんなルールだこれ
(s-split-words "ABCde ABC1 AbCd")    ; => ("AB" "Cde" "AB" "C1" "Ab" "Cd")
Ruby
s = "ABCde ABC1 AbCd"
s = s.gsub(/([[:upper:]])([[:upper:]][\d[:lower:]])/, '\1 \2')    # => "AB Cde AB C1 AbCd"
s = s.gsub(/([[:lower:]])([[:upper:]])/, '\1 \2')    # => "AB Cde AB C1 Ab Cd"
s.split(/[^[:word:]]+/)    # => ["AB", "Cde", "AB", "C1", "Ab", "Cd"]

ローワーキャメルケース化 (s-lower-camel-case)

EmacsLisp
(s-lower-camel-case "foo-bar")    ; => "fooBar"
ActiveSupport
"foo-bar".underscore.camelize(:lower)    # => "fooBar"

アッパーキャメルケース化 (s-upper-camel-case)

EmacsLisp
(s-upper-camel-case "foo-bar")    ; => "FooBar"
ActiveSupport
"foo-bar".underscore.camelize    # => "FooBar"

スネークケース化 (s-snake-case)

EmacsLisp
(s-snake-case "foo-bar")    ; => "foo_bar"
ActiveSupport
"foo-bar".underscore    # => "foo_bar"

ケバブケース化 (s-dashed-words)

EmacsLisp
(s-dashed-words "FooBar")    ; => "foo-bar"
ActiveSupport
"FooBar".underscore.dasherize    # => "foo-bar"

先頭の単語の最初だけ大文字 (s-capitalized-words)

EmacsLisp
(s-capitalized-words "FOO BAR")    ; => "Foo bar"
Ruby
words = "FOO BAR".split(/\s+/)
[words.first.capitalize, words.drop(1).collect(&:downcase)].join(" ")    # => "Foo bar"

単語の先頭だけ大文字 (s-titleized-words)

EmacsLisp
(s-titleized-words "foo bar")    ; => "Foo Bar"
Ruby
"foo bar".split(/\s+/).collect(&:capitalize) * " "    # => "Foo Bar"

先頭の文字だけ集める (s-word-initials)

EmacsLisp
(s-word-initials "foo bar")    ; => "fb"
Ruby
"foo bar".scan(/(\w)\w*/).join    # => "fb"

書式にキーワードを埋めて展開 (s-format)

EmacsLisp
;; alist
(s-format "${a}" 'aget '(("a" . "x") ("b" . "y")))    ; => "x"
;; sequence
(s-format "$0" 'elt ["x" "y"])    ; => "x"
;; hash
(setq v (make-hash-table :test 'equal))
(puthash "a" "x" v)
(puthash "b" "y" v)
(s-format "${a}" 'gethash v)    ; => "x"
Ruby
"%{a}" % {a: "x", b: "y"}    # => "x"
"%1$s" % ["x", "y"]    # => "x"

変数名を埋めて評価 (s-lex-format)

EmacsLisp
(setq a '(1 2 3))
(s-lex-format "a = ${a}")    ; => "a = (1 2 3)"
Ruby
a = [1, 2, 3]
"a = #{a}"    # => "a = [1, 2, 3]"

変数を埋める書式をコードに変換 (s-lex-fmt|expand)

EmacsLisp
(setq a '(1 . 2))    ; => (1 . 2)
(setq v (s-lex-fmt|expand "${a}"))    ; => (s-format "${a}" (quote aget) (list (cons "a" (format (if s-lex-value-as-lisp "%S" "%s") a))))
(eval v)    ; => "(1 . 2)"

マッチした個数を返す (s-count-matches)

EmacsLisp
(s-count-matches "\\w+" "a b c")    ; => 3
Ruby
"a b c".scan(/\w+/).count    # => 3

前後に文字列を追加 (s-wrap)

EmacsLisp
(s-wrap "foo" "(" ")")    ; => "(foo)"
Ruby
"(" + "foo" + ")"    # => "(foo)"