# Elispでstring-trimの代替を用意する方法

Date: 2020-08-10
URL: https://s.conao3.com/blog/2020/dc06b0
Author: conao3 (Naoya Yamashita)

# 背景

`string-trim` とは与えた文字列の先頭と末尾の空白文字っぽいものを削除してくれる `subr-x` に定義されている便利関数です。
しかし、 `string-trim` が `subr-x` に追加されたのはEmacs-24.4からなので、Emacs-24.4未満で動かしたいエクストリームパッケージはその恩恵を得ることができません。
簡単な関数なので何度か作ったのですが、いちいち自分のパッケージをgrepするのが面倒なので、ブログポストとして残しておきます。

# 実装

`string-trim` はサブルーチンとして `string-left` と `string-right` を組み合わせて実装されています。

```emacs-lisp
(defsubst string-trim-left (string &optional regexp)
  "Trim STRING of leading string matching REGEXP.

REGEXP defaults to \"[ \\t\\n\\r]+\"."
  (if (string-match (concat "\\`\\(?:" (or regexp "[ \t\n\r]+") "\\)") string)
      (substring string (match-end 0))
    string))

(defsubst string-trim-right (string &optional regexp)
  "Trim STRING of trailing string matching REGEXP.

REGEXP defaults to  \"[ \\t\\n\\r]+\"."
  (let ((i (string-match-p (concat "\\(?:" (or regexp "[ \t\n\r]+") "\\)\\'")
                           string)))
    (if i (substring string 0 i) string)))

(defsubst string-trim (string &optional trim-left trim-right)
  "Trim STRING of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.

TRIM-LEFT and TRIM-RIGHT default to \"[ \\t\\n\\r]+\"."
  (string-trim-left (string-trim-right string trim-right) trim-left))
```

つまり、これらを連結すればできます。

```emacs-lisp
(defun my--string-trim (str &optional trim-left trim-right)
  "Trim STR of leading and trailing strings matching TRIM-LEFT and TRIM-RIGHT.

TRIM-LEFT and TRIM-RIGHT default to \"[ \\t\\n\\r]+\".
Original function is `string-trim'.
This function is polyfill for Emacs<24.4."
  (let ((res str))
    (setq res (replace-regexp-in-string (or trim-left "\\`[ \t\n\r]*") "" res))
    (setq res (replace-regexp-in-string (or trim-right "[ \t\n\r]*\\'") "" res))
    res))
```

また、この実装では `replace-regexp-in-string` を2回実行していますが、正規表現を工夫すれば1回で良いです。

```emacs-lisp
(defun my--string-trim (str)
  "Trim STR of leading and trailing space like strings.

TRIM-LEFT and TRIM-RIGHT default to \"[ \\t\\n\\r]+\".
Original function is `string-trim'.
This function is polyfill for Emacs<24.4."
  (replace-regexp-in-string "\\`[ \t\n\r]*\\|[ \t\n\r]*\\'" "" str))
```

# まとめ

`string-trim` を実装しました。
もう一度書きますが、この関数は `subr-x` に定義されている関数なので、「Emacs-24.4未満で動かしたいんだけど」というエクストリームパッケージ用です。
正攻法としてはEmacsの要求バージョンを上げてしまうのが一番早いので、そこは留意して頂ければと思います。
