mod_sedでウェブを高速化(多分完結)

4月の末からいろいろやってるこの件。まぁ要するにですね、以下の文字列を

1        background-image:url(http://images.example.com/images/jp/bg-global.gif);
2        background-image:url(/images/jp/bg-global.gif);
3        background-image:url(images/jp/bg-global.gif);
4        background-image:url(hmages/jp/bg-global.gif);
5        background-image:url(tmages/jp/bg-global.gif);
6        background-image:url("/images/jp/bg-global.gif");
7        background-image:url('/images/jp/bg-global.gif');

こう変えたい。

1        background-image:url(http://images.example.com/images/jp/bg-global.gif);
2        background-image:url(http://images.example.com/images/jp/bg-global.gif);
3        background-image:url(http://images.example.com/images/jp/bg-global.gif);
4        background-image:url(http://images.example.com/hmages/jp/bg-global.gif);
5        background-image:url(http://images.example.com/tmages/jp/bg-global.gif);
6        background-image:url("http://images.example.com/images/jp/bg-global.gif");
7        background-image:url('http://images.example.com/images/jp/bg-global.gif');

面倒なことにいろんなパターンでURLが書かれているので、以下を実現する必要があります。

  1. httpが入ってるものは変換せずそのまま出す。(1行目)
  2. "で囲まれている場合は変換後も"で囲む。シングルクオートでも同じ。(6行目、7行目)
  3. /で始まっていても、/で始まっていなくても/を重ねることなく変換する。(2行目、3行目)

でもってこのところこれらを一行の正規表現で実現しようとしていたんですが、sedでは先読みの否定(?!pattern)が使えないみたい*1ので上記条件の1が実現できませんでした。

sedならどう実現するかってところに立ち返って考えてみると、sedの分岐を使えばいいということを思いつきました。
bコマンドですね。パターンにマッチした場合にラベルに分岐する機能。C言語的に書けばこんなです。

 if (httpが含まれている)
  なにもしない
 else
    s/ほげほげ/ふがふが/g

sedではこう書きます。

/http/ b nop
s/ほげほげ/ふがふが/g
:nop
:end

従って、最終型はこう。

   SetOutputFilter DEFLATE
   OutputSed   "/http/ b nop"
   OutputSed   "s/\(url(['\"]*\)\/*\(.*\.[gj][pin]e*[fg]\)/\1http:\/\/images.example.com\/\2/g"
   OutputSed   ":nop"
   OutputSed   ":end"
   AddoutputFilterByType Sed ; DEFLATE text/css

いやー若いころsed勉強しててよかった。
参考書はこちら。

sed & awkプログラミング 改訂版 (A nutshell handbook)

sed & awkプログラミング 改訂版 (A nutshell handbook)

sedパズルブック

sedパズルブック

*1:mod_rewriteやLocationMatchでは使える