LoginSignup
6
6

More than 5 years have passed since last update.

CoffeeScriptとかjavascriptでワイルドカードを正規表現に書き換える

Last updated at Posted at 2015-05-28

続き書いた

下記で言及したFileList作ってみた

前置き

なんか、Grunt, Gulp界隈、「タスクランナー疲れ」みたいなポストがちらほらありますな。それに乗じて(笑)rakeを勧めている人なんかもいらっしゃいますが、

「Perl, Ruby, Python はどれかひとつ覚えときゃいい」
「ほほう。じゃ、Perl分かるからスキップでいっか」

と何気なくRuby, Pythonをスルーしてしまったおじさんには悲しいのだ。と言うわけで、タスクランナーなんて使わずに、ちょっとした便利関数をrequireして、

forever start -c coffee /path/to/tools/automake.coffee

でいいんじゃね?(もちろん、automake.coffeeがタスクランナーっちゅうか、自製生書き監視&タスク管理スクリプトだよ)

で、そういうことをしようとすると、その「ちょっとした便利関数」にrakeっぽいFileListとか、run(target, depedencyfiles, {watch: on}, func)みたいなのが欲しくなる。まあ、ちょろちょろと空き時間に書いてアップしようと思うが、それで良くないかい?

そのための最初の「ちょっとした便利関数」

とりあえず、FileList作るんなら、ワイルドカード欲しいよね。asterisk, globstar, question, bracket, braceが使えればそれで良いよね。変換ルールは下記

正規表現と被る表記全部
エスケープしといた
*
[^/]* パス区切り以外の全ての0回以上繰り返し
**
.* パス区切りを含めた全ての0回以上繰り返し
?
[^/] パス区切り以外の全て(1文字)
{foo,bar}
(foo|bar) 選択
[a-z]
[a-z] つーか、触ってない!
文末
$ ワイルドカードの意味って、後方一致だよね

あれ? どこぞのシェルとかツールに採用されてる globstar「**」って、/path/**/hoge と書いたら /path/hoge にマッチすんの? するとしたらこれじゃ違うね。まあ、そこは突っ込みがあれば直す感じ。なんかシェルによって違うとかちらっと聞いたけどさ。

なんだかんだ言って直した方がよさげなので、/path/**/hoge と書いたら /path/hoge にマッチするようにした。

とゆーわけで、こいつだ。一般性が高いので、Javascript版も載せとくよ。

wildcard.coffee
y_combi = (func) ->
  return ((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )((p) ->
    return () ->
      return func(p(p)).apply(this,arguments)
  )


braces2parentheses = y_combi (func) ->
  return (str) ->
    dst = str
    result = str.match(/^([^\{]*)\{([^\}]*)\}(.*)$/)
    if result?
      dst = result[1]+'('+result[2].split(',').join('|')+')'+func(result[3])
    return dst


wildcard2regexstr = (str) ->
  str = str.replace /\\/g,'\\\\'
  str = str.replace /\+/g,'\\+'
  str = str.replace /\./g,'\\.'
  str = str.replace /\(/g,'\\('
  str = str.replace /\)/g,'\\)'
  str = str.replace /\^/g,'\\^'
  str = str.replace /\$/g,'\\\$'
  str = str.replace /\|/g,'\\|'
  str = braces2parentheses str
  str = str.replace /\?/g,'[^/]'
  str = str.replace /<</g,'<<2'
  str = str.replace /<<</g,'<<3'
  str = str.replace /\/\*\*\//g,'(/.<<</|/)'
  str = str.replace /\*/g,'[^/]+'
  str = str.replace /<<</g,'*'
  str = str.replace /<<2/g,'<<'
  str = str.replace /<<3/g,'<<<'
  str += '$'

wildcard2regex = (str) ->
  return new RegExp(wildcard2regexstr str)

#test

testtext = "src/*.{js,coffee}"
console.log testtext
regexstr = wildcard2regexstr testtext
regex = new RegExp(regexstr)
console.log regexstr

こっちがJavascript版。

wildcard.js
  var y_combi = function(func) {
    return (function(p) {
      return function() {
        return func(p(p)).apply(this, arguments);
      };
    })(function(p) {
      return function() {
        return func(p(p)).apply(this, arguments);
      };
    });
  };

  var braces2parentheses = y_combi(function(func) {
    return function(str) {
      var dst, result;
      dst = str;
      result = str.match(/^([^\{]*)\{([^\}]*)\}(.*)$/);
      if (result != null) {
        dst = result[1] + '(' + result[2].split(',').join('|') + ')' + func(result[3]);
      }
      return dst;
    };
  });

  wildcard2regexstr = function(str) {
    str = str.replace(/\\/g, '\\\\');
    str = str.replace(/\+/g, '\\+');
    str = str.replace(/\./g, '\\.');
    str = str.replace(/\(/g, '\\(');
    str = str.replace(/\)/g, '\\)');
    str = str.replace(/\^/g, '\\^');
    str = str.replace(/\$/g, '\\\$');
    str = str.replace(/\|/g, '\\|');
    str = braces2parentheses(str);
    str = str.replace(/\?/g, '[^/]');
    str = str.replace(/<</g, '<<2');
    str = str.replace(/<<</g, '<<3');
    str = str.replace(/\/\*\*\//g, '(/.<<</|/)');
    str = str.replace(/\*/g, '[^/]+');
    str = str.replace(/<<</g, '*');
    str = str.replace(/<<2/g, '<<');
    str = str.replace(/<<3/g, '<<<');
    return str += '$';
  };

  var wildcard2regex = function(str) {
    return new RegExp(wildcard2regexstr(str));
  };

//test

  var testtext = "src/*.{js,coffee}";
  console.log(testtext);
  var regexstr = wildcard2regexstr(testtext);
  var regex = new RegExp(regexstr);
  console.log(regexstr);
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6