Created
November 30, 2012 18:31
-
-
Save s-hiiragi/4177602 to your computer and use it in GitHub Desktop.
千反田える
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @name 千反田える.js | |
* @author s_hiiragi | |
* @created_date 2012/11/07 02:13 | |
*/ | |
/* Usage: | |
* | |
* node 千反田える.js {options} | |
* | |
* options: | |
* -d | --daiji | |
* 漢数字ではなく大字を使う | |
* | |
* num1, num2, ... | |
* num1, num2, ...について計算 | |
* 例) node 千反田える.js 1000 | |
* node 千反田える.js 1, 2, 3 | |
* | |
* begin ".." end, ... | |
* [begin .. end], ...について計算 | |
* 例) node 千反田える.js 1 .. 1000 | |
* | |
* [-b begin=1] [-e end=Infinity] | |
* [begin .. end]について計算 | |
* 例) node 千反田える.js -b 1 -e 1000 | |
* node 千反田える.js --begin 1 --end 1000 | |
*/ | |
function 漢数字(n) { | |
this.n = n; | |
} | |
漢数字.prototype = { | |
NUM: ['〇', '一', 'ニ', '三', '四', '五', '六', '七', '八', '九'], | |
KETA: ['〇', '一', '十', '百', '千', '万', '億'], | |
toString: function() { | |
if (this._str) return this._str; | |
this._str = this._toString(this.n); | |
return this._str; | |
}, | |
_toString: function(n) { | |
if (n == 0) return this.NUM[0]; | |
if (n == 1) return this.NUM[1]; | |
var s = String(n), len = s.length; | |
var res = []; | |
for (var i = 0; i < len; ++i) { | |
var keta = len - i; | |
var num = s[i]; | |
if (num == 0) continue; | |
if (num >= 2) res.push(this.NUM[num]); | |
if (keta >= 2) { | |
if (keta >= 5 && num == 1) res.push(this.NUM[1]); | |
res.push(this.KETA[keta]); | |
} | |
} | |
return res.join(''); | |
} | |
}; | |
function 大字(n) { | |
this.n = n; | |
} | |
大字.prototype = new 漢数字(0); | |
大字.prototype.NUM = ['零', '壱', '弐', '参', '肆', '伍', '陸', '漆', '捌', '玖' | |
]; | |
大字.prototype.KETA = ['零', '壱', '拾', '佰', '仟', '萬', '億']; | |
/* 兆以上 (漢数字/大字共通, int64で必要) | |
* 兆, 京, 垓, (じょ), 穣, 溝, 澗, 正, 載, 極, | |
* 恒河沙, 阿僧祇, 那由他, 不可思議, 無量大数 | |
*/ | |
/** | |
* 拡張RegExpクラス | |
*/ | |
function MyRegExp(re) { | |
var flags = (re.global ? 'g' : '') + | |
(re.ignoreCase ? 'i' : '') + | |
(re.multiline ? 'm' : ''); | |
re.compile(re.source, flags); | |
this._re = re; | |
this.lastIndex = 0; | |
} | |
MyRegExp.METACHAR_REPLACER = /[\[\](){}^$|\\+*?.]/g; | |
MyRegExp.escape = function(text) { | |
return text.replace(this.METACHAR_REPLACER, '\\$&'); | |
}; | |
MyRegExp.prototype = { | |
exec: function(text, index) { | |
var beginIndex; | |
if (this._re.global) { | |
beginIndex = typeof index != 'undefined' | |
? index : this.lastIndex; | |
this._re.lastIndex = beginIndex; | |
} | |
var matches = this._re.exec(text); | |
if (!matches) return null; | |
if (this._re.global) { | |
var lastIndex = this._re.lastIndex; | |
this.lastIndex = lastIndex; | |
matches.beginIndex = beginIndex; | |
matches.matchIndex = matches.index; | |
matches.nextIndex = lastIndex; | |
} | |
return matches; | |
} | |
}; | |
/** | |
* スキャナクラス | |
*/ | |
function Scanner(name, re) { | |
this.name = name; | |
if (typeof re == 'string') { | |
re = new RegExp('^(' + MyRegExp.escape(re) + ')', 'g'); | |
} | |
this._re = new MyRegExp(re); | |
} | |
Scanner.prototype = { | |
deserializer: function(callback) { | |
this._deserializer = callback; | |
return this; | |
}, | |
scan: function(text) { | |
var matches = this._re.exec(text, 0); | |
if (!matches) return null; | |
var token = new Token(this, matches[1]); | |
if (this._deserializer) { | |
token.value = this._deserializer(token.str); | |
} | |
return { | |
token: token, | |
// next: text.substring(matches.nextIndex) | |
nextIndex: matches.nextIndex | |
}; | |
} | |
}; | |
/** | |
* トークンクラス | |
*/ | |
function Token(scanner, str) { | |
this['is' + scanner.name] = true; | |
this.str = str; | |
} | |
Token.prototype = {}; | |
/** | |
* Rangeクラス | |
*/ | |
function Range(begin, end) { | |
this.begin = begin != null ? begin : 1; | |
this.end = end != null ? end : Infinity; | |
} | |
Range.prototype = { | |
toString: function() { | |
return '[' + begin + ' .. ' + end + ']'; | |
} | |
}; | |
/** | |
* rangeOpt | |
*/ | |
var rangeOpt = { | |
_Scanners: [ | |
new Scanner('Integer', /^(\d+)/g) | |
.deserializer(function(t) { return Number(t); }), | |
new Scanner('RangeMark', '..'), | |
new Scanner('Comma', ',') | |
], | |
_input: null, | |
_pos: 0, | |
get _curInput() { | |
if (this._pos == this._cur_pos) { | |
return this._cur_input; | |
} | |
this._cur_pos = this._pos; | |
this._cur_input = this._input.substring(this._pos); | |
return this._cur_input; | |
}, | |
get _isEOF() { | |
return (this._pos >= this._input.length); | |
}, | |
parse: function(args) { | |
var tokens = this._tokenize(args.join(' ')); | |
//console.log('tokens = ', tokens); | |
if (tokens.length == 0) return null; | |
var numOrRanges = this._parse(tokens); | |
//console.log('numOrRanges', numOrRanges); | |
return numOrRanges; | |
}, | |
_tokenize: function(command) { | |
//console.log('command', '"' + command + '"'); | |
this._input = command; | |
this._pos = 0; | |
this._cur_pos = -1; | |
var tokens = []; | |
while (true) { | |
this._skip_wsp(); | |
if (this._isEOF) break; | |
tokens.push(this._scan()); | |
} | |
return tokens; | |
}, | |
_skip_wsp: function() { | |
var re = new MyRegExp(/^\s+/g); | |
var matches = re.exec(this._curInput); | |
if (!matches) return; | |
this._pos += matches.nextIndex; | |
}, | |
_scan: function() { | |
//console.log('_scan: "' + this._curInput + '"'); | |
var token; | |
var that = this; | |
this._Scanners.some(function(scanner) { | |
var res = scanner.scan(that._curInput); | |
if (!res) return false; | |
token = res.token; | |
that._pos += res.nextIndex; | |
return true; | |
}); | |
if (!token) { | |
throw new Error('unknown char [' + that._curInput + ']'); | |
} | |
return token; | |
}, | |
_parse: function(tokens) { | |
var numOrRanges = []; | |
while (tokens.length >= 1) | |
{ | |
var nor = this._getNumOrRange(tokens); | |
if (!nor) break; | |
numOrRanges.push(nor); | |
if (tokens[0] && tokens[0].isComma) | |
tokens.shift(); | |
} | |
if (numOrRanges.length == 0) | |
throw new Error('no token'); | |
return numOrRanges; | |
}, | |
_getNumOrRange: function(tokens) { | |
var t = tokens[0]; | |
if (t.isInteger) { | |
var t2 = tokens[1]; | |
// Number [EOF] | |
if (!t2) return tokens.shift().value; | |
if (t2.isRangeMark) { | |
var t3 = tokens[2]; | |
// Number .. [EOF] | |
if (!t3) { | |
var begin = tokens.shift().value; | |
tokens.shift(); | |
return new Range(begin, null); | |
} | |
// Number .. Number | |
if (t3.isInteger) { | |
var begin = tokens.shift().value; | |
tokens.shift(); | |
var end = tokens.shift().value; | |
return new Range(begin, end); | |
} | |
// Number .. {next} | |
else { | |
var begin = tokens.shift().value; | |
tokens.shift(); | |
return new Range(begin, null); | |
} | |
} | |
// Number {next} | |
else return tokens.shift().value; | |
} | |
else if (t.isRangeMark) { | |
var t2 = tokens[1]; | |
// .. [EOF] | |
if (!t2) throw new Error('no token'); | |
// .. Number | |
if (t2.isInteger) { | |
tokens.shift(); | |
var end = tokens.shift().value; | |
return new Range(null, end); | |
} | |
// .. ??? | |
else throw new Error('unknown token', t2); | |
} | |
else throw new Error('unknown token', t); | |
} | |
}; | |
var assert = require('assert'); | |
// rangeOpt test | |
// | |
// 正常系 | |
assert.equal(rangeOpt.parse([]), null); | |
assert.deepEqual(rangeOpt.parse(['1']) , [1]); | |
assert.deepEqual(rangeOpt.parse(['1', '2', '3']) , [1, 2, 3]); | |
assert.deepEqual(rangeOpt.parse(['1', ',', '2', ',', '3']) , [1, 2, 3]); | |
assert.deepEqual(rangeOpt.parse(['1,2,3']) , [1, 2, 3]); | |
assert.deepEqual(rangeOpt.parse(['1', '..']) , [new Range(1)]); | |
assert.deepEqual(rangeOpt.parse(['1..']) , [new Range(1)]); | |
assert.deepEqual(rangeOpt.parse(['1', '..', ',', '2']) , [new Range(1), 2]); | |
assert.deepEqual(rangeOpt.parse(['1..,2']) , [new Range(1), 2]); | |
assert.deepEqual(rangeOpt.parse(['1', '..', '2']) , [new Range(1, 2)]); | |
assert.deepEqual(rangeOpt.parse(['1..2']) , [new Range(1, 2)]); | |
assert.deepEqual(rangeOpt.parse(['1', '..', '2', '3']) , [new Range(1, 2), 3]); | |
assert.deepEqual(rangeOpt.parse(['1', '..', '2', ',', '3']) , [new Range(1, 2), 3]); | |
assert.deepEqual(rangeOpt.parse(['1..2,3']) , [new Range(1, 2), 3]); | |
assert.deepEqual(rangeOpt.parse(['..', '1']) , [new Range(null, 1)]); | |
assert.deepEqual(rangeOpt.parse(['..1']) , [new Range(null, 1)]); | |
assert.deepEqual(rangeOpt.parse(['..', '1', '2']) , [new Range(null, 1), 2]); | |
assert.deepEqual(rangeOpt.parse(['..', '1', ',' , '2']) , [new Range(null, 1), 2]); | |
assert.deepEqual(rangeOpt.parse(['..1,2']) , [new Range(null, 1), 2]); | |
// | |
// 異常系 | |
assert.throws(function() { | |
rangeOpt.parse(['hoge']); | |
}, Error); | |
// | |
// /rangeOpt test | |
var opts = require('opts'); | |
opts.parse([ | |
{ | |
'short': 'd', | |
'long': 'daiji', | |
'description': 'use 大字', | |
'value': false, | |
'require': false | |
}, | |
{ | |
'short': 'b', | |
'long': 'begin', | |
'description': 'begin number (default is 0)', | |
'value': true, | |
'required': false | |
}, { | |
'short': 'e', | |
'long': 'end', | |
'description': 'end number (default is Infinity)', | |
'value': true, | |
'required': false | |
} | |
]); | |
var alp = [ | |
'えー', 'びー', 'しー', 'でぃー', 'いー', 'えふ', 'じー', | |
'えいち', 'あい', 'じぇい', 'けー', 'える', 'えむ', 'えぬ', | |
'おー', 'ぴー', 'きゅー', 'あーる', 'えす', 'てぃー', 'ゆー', | |
'ぶい', 'だぶりゅー', 'えっくす', 'わい', 'ぜっと' | |
]; | |
var Num2kanji = opts.get('daiji') ? 大字 : 漢数字; | |
function print_chitanda(begin, end) { | |
for (var i = begin; i <= end; ++i) { | |
var s = new Num2kanji(i) + '反田' + alp[(i-1) % alp.length]; | |
console.log(s); | |
} | |
} | |
var numOrRanges = rangeOpt.parse(opts.args()); | |
if (numOrRanges) { | |
numOrRanges.forEach(function(nor) { | |
if (typeof nor == 'number') { | |
print_chitanda(nor, nor); | |
} else { | |
print_chitanda(nor.begin, nor.end); | |
} | |
}); | |
} else { | |
var begin = Number(opts.get('begin')); | |
if (isNaN(begin)) begin = 1; | |
var end = opts.get('end'); | |
if (isNaN(end)) end = Infinity; | |
print_chitanda(begin, end); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment