5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CoffeeScript や Javascript (node.js) でグロブ(ワイルドカード)が使える FileList

Last updated at Posted at 2015-05-28

ワイルドカードを正規表現に書き換えるやつの続き。
とゆーわけで、CoffeeScript や Javascript (node.js) で、グロブが使える FileList。rubyのrakeで使えるのがどんなやつかよく知らないけど、とりあえず、移植じゃないもーん。(って、ちょっとドキュメント覗いてみたら、遅延評価な感じで、しかもちょこざいな機能が色々あるのね。まねしないぞ。……しないぞ! 絶対にな!)

asterisk *, globstar **, question ?, bracket [a-zA-Z], brace {foo|bar} が使えます。

  • 第1引数はグロブの文字列(か、正規表現オブジェクトもOK)
  • 第2引数は探索のベースとなるパス(省略すれば、カレントです)
  • 返値はマッチするファイルのフルパス文字列のArray
    ま、よしなに。
arr = FileList("src/**/temp_*.{js,coffee}")

みたいな感じでさくっとディレクトリ走査。ま、GulpをCoffeeScriptに置き換える以外にも、これなら使い途がありましょう。

FileList.coffee
fs = require('fs')

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)

FileList_inside = y_combi (func) ->
  return (srcpath, regex, pathregex) ->
    arr = []
    if not fs.existsSync srcpath
      return -1
    filearray = fs.readdirSync srcpath
    for fileordir in filearray
      fname = srcpath+'/'+fileordir
      statresult = fs.statSync fname
      if statresult.isFile()
        if regex.test fname
          if pathregex.test fname
            arr.push(fname)
      else if statresult.isDirectory()
        arr = arr.concat func(fname,regex,pathregex)
    return arr

FileList = (pathname, basepath = null) ->
  judgetype = Object.prototype.toString.call(pathname).slice(8, -1)
  if not basepath?
    basepath = process.cwd()
  else if basepath == '.'
    basepath = process.cwd()
  else if /^\.\//.test basepath
    basepath = basepath.replace(/^\./,process.cwd())
  else if /^\.\./.test basepath
    basepath = process.cwd()+'/'+basepath
  while(/\/\.\./.test basepath)
    basepath = basepath.replace(/\/[^\/]+\/\.\./,'')
  basepath = basepath.replace(/\/$/,'')
  pathregex = basepath
  basepath = basepath.replace(/[\*\?\[\{].*$/,'')
  basepath = basepath.replace(/\/[^\/]*$/,'')
  pathregex = '^'+(wildcard2regexstr pathregex).replace(/\$$/,'')+'/'
  pathregex = new RegExp(pathregex)

  switch judgetype
    when 'RegExp'
      regex = pathname
    when 'String'
      regex = wildcard2regex pathname
    else
      console.log 'error'
      process.exit 1
  FileList_inside basepath,regex,pathregex

# test


for fname in FileList("*.coffee",'../../**/a??')
  console.log fname

JavaScript版。

FileList.js
  var fs = require('fs');

  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;
    };
  });

  var 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));
  };

  var FileList_inside = y_combi(function(func) {
    return function(srcpath, regex, pathregex) {
      var arr, filearray, fileordir, fname, i, len, statresult;
      arr = [];
      if (!fs.existsSync(srcpath)) {
        return -1;
      }
      filearray = fs.readdirSync(srcpath);
      for (i = 0, len = filearray.length; i < len; i++) {
        fileordir = filearray[i];
        fname = srcpath + '/' + fileordir;
        statresult = fs.statSync(fname);
        if (statresult.isFile()) {
          if (regex.test(fname)) {
            if (pathregex.test(fname)) {
              arr.push(fname);
            }
          }
        } else if (statresult.isDirectory()) {
          arr = arr.concat(func(fname, regex, pathregex));
        }
      }
      return arr;
    };
  });

  var FileList = function(pathname, basepath) {
    var judgetype, pathregex, regex;
    if (basepath == null) {
      basepath = null;
    }
    judgetype = Object.prototype.toString.call(pathname).slice(8, -1);
    if (basepath == null) {
      basepath = process.cwd();
    } else if (basepath === '.') {
      basepath = process.cwd();
    } else if (/^\.\//.test(basepath)) {
      basepath = basepath.replace(/^\./, process.cwd());
    } else if (/^\.\./.test(basepath)) {
      basepath = process.cwd() + '/' + basepath;
    }
    while (/\/\.\./.test(basepath)) {
      basepath = basepath.replace(/\/[^\/]+\/\.\./, '');
    }
    basepath = basepath.replace(/\/$/, '');
    pathregex = basepath;
    basepath = basepath.replace(/[\*\?\[\{].*$/, '');
    basepath = basepath.replace(/\/[^\/]*$/, '');
    pathregex = '^' + (wildcard2regexstr(pathregex)).replace(/\$$/, '') + '/';
    pathregex = new RegExp(pathregex);
    switch (judgetype) {
      case 'RegExp':
        regex = pathname;
        break;
      case 'String':
        regex = wildcard2regex(pathname);
        break;
      default:
        console.log('error');
        process.exit(1);
    }
    return FileList_inside(basepath, regex, pathregex);
  };

  var i,len;
  var ref = FileList("*.coffee", '../../**/a??');
  for (i = 0, len = ref.length; i < len; i++) {
    fname = ref[i];
    console.log(fname);
  }
5
5
2

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
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?