printfの自作
Posted feedbacks - Ruby
Rubyのsprintfの仕様に従って実装しました. pフラグは仕様が不明瞭だったので実装しませんでした.
format系のメソッドは仕様不可ということで, 指数表示変換は自前で容易したのでバグが潜在している可能性が高いです.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | #%[フラグ][最小フィールド幅][.精度][長さ修飾子]変換指定子
MATCH_STR = '%([\+\-\s#0\*]*)(\d*)((?:\.\d+)?)([hliztl]*)([\w%]*)'
def mysprintf(*argv)
def check_flag(str, flag, width, precision)
str = str.to_s
width = width.to_i
pos = flag.include?('-')
sign = (/\A([\-\+])\w+\z/ =~ str or flag.include?('+'))
zero = flag.include?('0')
w = (width.to_i > str.size ? width-str.size : 0)
if sign
s = (str.to_i.abs >= 0 ? '+' : '-')
w = (w >= 1 ? w - 1 : 0)
else
s = ''
end
num = (/\.(\d+)/ =~ precision and $1.to_i <= w and $1.to_i > 0) ? $i.to_i+1 : 0
filler = (zero ? '0' : ' ')*(w-num) + '0'*num
"#{pos ? '' : filler}#{s}#{str}#{pos ? filler : ''}"
end
def check_spec(str, spec, opt)
def exp_expr(n) #有理数を指数表示に変換
i = 0
break if eval("10**#{n.abs > 1 ? '1' : '0'}*10**(i#{n.abs > 1 ? '+= 1) >' : '-= 1) <='}#{'-1*' if n < 0}n") while 1
"#{n.quo(10**(i+1))}e#{i+1}"
end
def e_flag(str)
if str.include?('e')
if str.include('.')
str
else
"#{str.split('e')[0]}.e#{str.split('e')[1]}"
end
else
exp_expr(str.to_f)
end
end
def g_flag(str)
str.to_f < 10e-3 ? e_flag(str) : str.to_f.to_s
end
if opt
case spec
when 'b': "0b#{str.to_i.to_s(2)}"
when 'o': "0#{str.to_i.oct}"
when 'x': "0x#{str.to_i.hex}"
when 'X': "0x#{str.to_i.hex}".upcase
when 'f': str.include('.') ? str : "#{str}."
when 'F': (str.include('.') ? str : "#{str}.").upcase
when 'e': e_flag(str)
when 'E': e_flag(str).upcase
when 'g': g_flag(str)
when 'G': g_flag(str).upcase
else
end
else
case spec
when 'd': str.to_i
when 'i': str.to_i
when 'u': (str.to_i < 0 ? 2**32 + str.to_i : str.to_i)
when 'o': str.to_i.oct
when 'x': str.to_i.hex
when 'X': str.to_i.hex.to_s.upcase
when 'e': e_flag(str)
when 'E': e_flag(str).upcase
when 'f': str.to_f
when 'F': str.to_f.to_s.upcase
when 'g': g_flag(str)
when 'G': g_flag(str).upcase
when 'c': str[0].chr
when 's': str.to_s
when '%': '%'
else
raise ArgumentError.new("malformed format string - #{spec}")
end
end
end
f = argv[0].match(/\A#{MATCH_STR}\z/)[1..-1]
if f[0].include?('*')
str = argv[2].to_s
width = argv[1]
else
str = argv[1].to_s
width = f[1]
end
if /\A[di]\z/ =~ f[4] and str.to_f != str.to_i
raise ArgumentError.new("invalid value for Integer: #{str}")
end
flag = f[0]
prec = f[2]
spec = f[4]
opt = f[0].include?('#')
check_flag(check_spec(str, spec, opt), flag, width, prec)
end
p mysprintf("%%", "testtest") # => "%"
p sprintf("%%", "testtest") # => "%"
p mysprintf("%5.0u", '-1') # => "4294967295"
p sprintf("%5.0u", '-1') # => "4294967295"
p mysprintf("% 2d", "1", '2') # => " 1"
p sprintf("% 2d", "1", '2') # => " 1"
|

yappy
#4119()
[
C
]
Rating-4/18=-0.22
Rating-4/18=-0.22-0+
[ reply ]