svgファイルを正規表現で置換して最適化する

アイコンアセットを制作した時のお話。

配布用のsvgファイルを出力した際、空のグループやガイド画像の参照まで書き出されてしまったため、これをテキストエディタの正規表現で置換する方法を残しておきます。

本当はツール側で出力内容を制御したいところですが、私の環境ではその手段がなく、かといって出力の度に不要なレイヤーを消すのも手間なので…少数のファイルであればweb上の最適化ツールで事足りそうですが、今回は沢山のファイルを処理したかったのでこの方法を採りました。

ただし、私は正規表現やsvgに関して全くの素人です。他のフォーマットや環境での動作は保証できませんし、「自分のところでは動いたからヨシ!」という精神で記事を書いています。そのためバックアップは必ず取り、自己責任でのご利用をお願いします。

なお、私の使用したエディタはSublime Text 3になります。

空の行を削除する

検索:

^\s*$\s?

空行(あるいはスペースやタブのみの行)を検索する正規表現です。置換後のテキストを未記入で実行することで対象を削除できます。

本記事ではなるべく空行が出ないようパターンを記述していますが、もし空行が発生した場合はこちらで処理してください。

空のグループを削除する

例:

<g id="test_x5F_01">
</g>

検索:

^\s*<g.*?>\s*</g>\s?

何も含まれていないレイヤーが出力され、空の<g>タグが生成された場合。(これくらいはツール側で出力を制御させてほしい)

中に文字が含まれていない<g>タグを検索しているため、空のグループが入れ子になっている場合は末端しか削除されない点に注意。

非表示のグループを削除する

例:

<g id="edit_1_" display="none">
        <g display="inline">
                <polyline fill="#204080" points="235.001,720 160.001,670 205.001,670 235.001,690"/>
        </g>
</g>

検索:

^(\t*)<g.*?display="none"[\s\S]*?^\1</g>\s?

レイヤーを非表示にして出力したらdisplay="none"がついた上で出力されてしまった場合。

このパターンではdisplay="none"が指定されたタグ開始から、同じインデント階層の閉じタグまでを検索します。流石にインデントがズレているような状況はないと思うので想定していません。ご了承を。

タグ末尾の空白を取り除く

例:

<polygon fill="#204080" points="160,230 160,250 340,250 660,250 840,250 840,230          "/>

検索:

\s+"/>

置換:

"/>

なぜか出力した座標情報の末尾にスペースやタブが含まれているケース。謎です。

タグの末尾にあることを前提としているので他の情報が後に続くと検索できません。素人なのでsvgの仕様上そういうことがあるのかも分からない…でも自分のところでは動いたからヨシ!

fillの色指定を取り除く

例:

<g id="test_x5F_01">
        <g>
                <circle fill="#204080" cx="320" cy="650" r="50"/>
                <circle fill="#204080" cx="680" cy="650" r="50"/>
        </g>
</g>

検索:

fill=".*?"\s*

こちらは単色アイコンなどで色指定が不要な場合に使います。

一応fill="red"といった色指定の場合でも置換可能です。

コメントアウトを削除する

例:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1000px"
         height="1000px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">

検索パターン:

^<!--[\s|\S]*?-->$\s?

出力したソフトによって差し込まれたコメントアウトを削除したい場合。(未だにCS6にしがみついていることがバレちゃう…)

こちらは行全体、もしくは複数行に跨るコメントを検索しています。部分的なコメントを削除したい場合は上記パターンを置換した上で<!--[\s|\S]*?-->を対象に置換してください。先にこちらで置換すると一行or複数行コメントで空行が発生します。

タグ内の改行を取り除く

<g id="ship_x5F_01">
        <g>
                <path fill="#204080" d="M580.002,669.935V620h-50v49.945c-98.928-0.611-252.847-8.101-375-99.945l-30,35
                        c68.549,33.842,99.424,75.091,133.827,115h271.173h50h234.076c38.695-49.001,60.924-90,60.924-90
                        C759.834,664.945,666.553,669.417,580.002,669.935z"/>
        </g>
</g>

検索:

(?<=[^>\s])\s*[\r\n|\r|\n]+\s*(?=[^<\s])

置換:

 

座標データなどの一行が長い箇所で改行が挟まれており、これを削除したい場合。分かりにくいですが置換後に半角スペース1つを指定しています。

整形用の改行を削除すべきかは微妙なところですが、ひとまず上記のパターンでタグとは無関係な改行を削除できると思います。ただし一行がとんでもなく長くなっても知らないです。

オマケ:その他の不要らしい記述の削除

検索:

<\?xml version="1.0".*?encoding="utf-8".*?\?>\s?
<!DOCTYPE svg PUBLIC.*?>\s?
\s*x="0px"\s*y="0px"
\s*enable-background=".*?"
\s*xml:space="preserve"

svgファイルの最適化を調べていた際に見かけた、どうやら不要らしい記述を削除するパターン。svgの仕様に関する知識をそもそも持ち合わせていないため、どれをどういう理由で削っていいのかは分かってないです。後日改めて調べる…かもしれません。

3段目の\s*x="0px"\s*y="0px"はいかにも他のデータに誤爆しそうなので、安全にいきたい場合は下記のような指定にした方がよさそうです。

検索:

(<svg.*?)(\s*x="0px"\s*y="0px")

置換:

\1

あとがき

以上、正規表現によるsvgの最適化でした。

記事を書くにあたって調べているうちに項目が増え、結局「これも全部手動でやるのは大変だな…」となって最終的に簡易ツールを作りました。流石に人様にお出しできるようなものじゃないですが、自分のsvgファイルくらいは一括で最適化できるようになりました、たぶん。

正規表現…たまに使うことはあるものの、そもそもコーディングすることが稀なので全部忘れてしまい、毎回ゼロからのスタートです。ぱっと見が呪文なので、今回の内容も数カ月後には暗号になっているかもしれません。