今回はノンプログラマー向けの正規表現入門記事その2です。
ノンプログラマーのための正規表現入門 1の続編で、先日書いたPhotoshop/JSX: フォルダ内の画像を開き、調整レイヤーを追加して保存するのコードを改善する内容となります。
前回のコード
上記の記事をご覧の上お読みいただけると分かりやすいかと思います。
さて、前回の記事では最終的に下記のようなコードとなりました。
(function () { var folder = Folder.selectDialog('画像があるフォルダを選択してください'); if (!folder) return; var files = folder.getFiles(/jpe?g/); for (var i = 0; i < files.length; i++) { var file = files[i]; app.open(file); app.doAction('add_adjustment_layer', 'MyAction'); var exportPath = file.path + '/' + file.name.replace(/jpe?g/, ''); app.activeDocument.saveAs(new File(exportPath)); } })();
一読して「このコード、問題があるぞ」と思った方もおられると思います。正規表現/jpe?g/
の部分です。その問題と、それに対処するようコードを修正していきましょう。
修正、その前に
コード修正は闇雲に行ってはいけません。問題を把握した上で適切に対処していきましょう。
フォルダ内の画像ファイルを読み込む部分だけを取り出して実行してみましょう。デカルトの言うように、困難は分割せよです。
(function () { var folder = Folder.selectDialog('画像があるフォルダを選択してください'); if (!folder) return; var files = folder.getFiles(/jpe?g/); alert(files); //ここを追加 })();
for文の処理をトルツメし、alert(files);
を追加しました。alertデバッグ
は原始的なデバッグ方法ですが、手軽なので簡単なデバッグには向いています。
このコードを使って下記ファイルが入っているフォルダで実験してみます。(imgがフォルダ名)
img ├── a.jpg ├── b.jpeg └── c.mov
- Photoshopのメニューバーからでファイル > スクリプト > 参照でJSXを実行します。
- 「画像があるフォルダを選択してみましょう」とダイアログが表示されるので、デスクトップにあるimgフォルダを選択し開くを押します。
- アラートウィンドウに下記文字が表示されます。
~/Desktop/img/a.jpg,~/Desktop/img/b.jpeg
拡張子jpg
とjpeg
ともに配列に格納されていますね。また拡張子mov
はちゃんと除外されています。
一見問題なさそうですね、どこが悪いのでしょう。
問題のあるパターンマッチ
続けて、デスクトップにあるこんなフォルダで試してみましょう。
img ├── a.jpg ├── b.jpeg └── jpg_dayo.mov
再度スクリプトを実行してみましょう。こんなアラートが表示されます。
~/Desktop/img/a.jpg,~/Desktop/img/b.jpeg,~/Desktop/img/jpg_dayo.mov
拡張子mov
も格納されてしまいました。なぜでしょう。
正規表現/jpe?g/
は文字列の中にjpg
とjpeg
があれば、場所にかかわらずマッチしてしまいます。jpg_dayo.mov
はさすがにわざとらしいですが、こんなケースはいかがでしょう。
デスクトップにjpg
フォルダを作った場合です。
jpg ├── a.txt ├── b.gif ├── c.pdf └── e.css
アラートウィンドウは下記のようになります。
~/Desktop/jpg/a.txt,~/Desktop/jpg/b.gif,~/Desktop/jpg/c.pdf,~/Desktop/jpg/e.css
拡張子はjpg
でもjpeg
でもありませんが、すべてマッチしてしまいました!これはまずいですね。パスの中にあるjpg
フォルダに反応してしまったわけですね。
さあ、これを修正しましょう。
マッチする場所を指定する
いままでのコードでは途中のjpg
とjpeg
に反応してしまったのが問題でしたね。ということはパスの最後が.jpg
か.jpeg
になっているというパターンを指定してあげれば良さそうです。
修正前 | 修正後 |
---|---|
/jpe?g/ | /\.jpe?g$/ |
こんな修正を施しました。正規表現の頭に\.
を、最後に$
を追加しただけです。簡単ですね。
ここで追加した箇所を説明しましょう。
追加した文字 | 意味 |
---|---|
\. | ドットを表現します |
$ | 行末を表現するメタ文字です |
\.
のバックスラッシュはエスケープ文字といい、その後に続く文字はメタ文字じゃないよと伝える記号になります。バックスラッシュを使わない.
は改行文字以外のどの1文字にもマッチするメタ文字です。
つまり/\.jpe?g$/
はパスの最後が.jpg
と、パスの最後が.jpeg
にマッチするということになります。これでパスの途中やファイル名にjpg
とjpeg
が入ってても安心ですね。さあ、再度試してみましょう。
imgフォルダを指定したときは下記のようにjpg_dayo.mov
を除外してくれました。
~/Desktop/img/a.jpg,~/Desktop/img/b.jpeg
jpgフォルダを指定したときは、フォルダ内に拡張子jpg
、jpeg
がないので空になります。
これで良さそうですね!
修正する
先程の修正を施したスクリプトは下記のようになります。
(function () { var folder = Folder.selectDialog('画像があるフォルダを選択してください'); if (!folder) return; var files = folder.getFiles(/\.jpe?g$/); for (var i = 0; i < files.length; i++) { var file = files[i]; app.open(file); app.doAction('add_adjustment_layer', 'MyAction'); var exportPath = file.path + '/' + file.name.replace(/\.jpe?g$/, ''); app.activeDocument.saveAs(new File(exportPath)); } })();
しかし/\.jpe?g$/
が2回出てくるのもキレイではないですね。こんな感じで変数re
に正規表現をまとめてみましょう。
(function () { var folder = Folder.selectDialog('画像があるフォルダを選択してください'); if (!folder) return; var re = /\.jpe?g$/; var files = folder.getFiles(re); for (var i = 0; i < files.length; i++) { var file = files[i]; app.open(file); app.doAction('add_adjustment_layer', 'MyAction'); var exportPath = file.path + '/' + file.name.replace(re, ''); app.activeDocument.saveAs(new File(exportPath)); } })();
これで完成です!
まとめ
JSXは使い捨てのツールとして作成する場合も多いので、運用でカバーしても良いと思います。特に今回はユーザーもケースも限定的だったため、前回のコードでも悪くはないと思いますが、正規表現を見直すことでより良いコードになりました。
正規表現はとても奥深い世界なので、興味が出たら勉強してみることをオススメします。