Sassで文字列の置換を行うユーザー定義関数

Sass 3.3で入る予定の文字列関数の使い道を色々考えているけど、まったく「これは!」みたいなのが思いつかない。なので、実際に利用しがいがあるかどうかは置いておいて、色々作ってみようかなと考えている。まずは文字列の置換。

// str-replace() - Replace in a string
//
// @param {string}  $string    String that you want to replace
// @param {string}  $substr    String that is to be replaced by `$newsubstr`
// @param {string}  $newsubstr String that replaces `$substr`
// @param {number*} $all       Flag for replacing all (1+) or not (0)
// @return {string}
@function str-replace($string, $substr, $newsubstr, $all: 0) {
  $position-found: str-index($string, $substr);
  $processed: ();

  @while ($position-found > 0) {
    $length-substr: str-length($substr);
    $processed: append($processed, str-slice($string, 0, $position-found - 1));
    $processed: append($processed, $newsubstr);
    $string: str-slice($string, $position-found + $length-substr);
    $position-found: 0;

    @if ($all > 0) {
      $position-found: str-index($string, $substr);
    }
  }

  $processed: append($processed, $string);
  $string: "";

  @each $s in $processed {
    $string: #{$string}#{$s};
  }

  @return $string;
}

str-index()で置換対象文字列$substr見つけたら、$substrまでを抜き出したのと置換後文字列$newstrをリストである$processedに追加していくという作業を行うだけ。最後に$processedを連結して返す。$allは全置換を行うかどうかのフラグで、0か省略した場合は最初の1つだけ置換する。

.test {
  margin: str-replace("1em 2em", "em", "rem", 1);
}

と書くと、

.test {
  margin: 1rem 2rem; }

となる。この利用例にまったく意味はない。


こういう汎用的であることを意識したユーザー定義関数を作っておいて@importするというのもそれほど悪くはなさそう。しかし、ミックスインのように即戦力ではないので、別に分けて管理してもメリットを得る機会はほとんどなさそう。かといって毎回一から書くのでは面倒臭いので、コアの部分をコード・スニペットとしてどっかに置いといて、複雑な特化型ユーザー定義関数を書く時に引っ張り出してきて使うというのが理にかなっている。と感じた。