ここ→
配列操作の比較表に触発されて、Rubyの文字列メソッドの対応物をJavaとHaskellで探してみました。
Javaの文字列処理がそれほど高機能じゃないのはある程度想定内だったけど、Haskellもなかなか1対1の対応物がない。
lines,unlinesとか逆にあまったけど。
そもそもHaskellのソレって文字列処理用っていうよりほとんど汎用リスト操作関数なわけで。
Haskellって
「汎用性の高い関数を用意したから自由に組み合わせて使ってね」
って思想だと思うわけで。
カリー化された関数の強力な応用力とあいまってこれはこれで一つの便利さの方向性だとはおもう。
ただこれの欠点は
「もっとエレガントで短い書き方があるんじゃないか?」
って不安がいつまでも付きまとう事。
(しかもタチの悪い事にパズルみたいで楽しすぎる!)
自分の修行が足りなくてイディオムを知らないせいもあるけどね。
(これ調べてるうちに、
HaskellでLhaにもいろいろ直したいところが!)
Javaのパッケージ名やHaskellのモジュール名を明示するため、必要なものは完全名で書きました。
(実際ほとんどの場合ソースの頭でimport文を使って短くかけるようにします。)
Ruby (String) |
Java |
Haskell |
s = "abc" |
String s = "abc" |
s = "abc" |
s = x + y |
s = x + y |
s = x ++ y |
s == x |
s.equals(x)
|
s == x
|
s % [x, y]
sprintf(s, x, y)
|
String.format(s, x, y)//J2SE5.0より
|
Text.Printf.printf s x y |
[x, y, z].join(s) |
|
foldr1 (¥a b->a ++ s ++ b) [x,y,z]
|
s.capitalize |
|
|
s.capitalize! |
|
|
s.casecmp(x) |
// s.equalsIgnoreCase(x)
// ってのがあるけど同値判定だけだし、、
|
|
s.center(x) |
|
|
s.chomp |
|
|
s.chomp! |
|
|
s.chop |
|
init s
|
s.chop! |
|
|
s.clear |
// sbはStringBuffer型
sb.setLength(0);
|
|
s.concat(x) |
// sbはStringBuffer型
sb.append(x);
|
|
s.count(x) |
|
length filter (flip elem x) s |
s.crypt(x) |
|
|
s.delete(x) |
|
filter (flip notElem x) s |
s.delete!(x) |
|
|
s.downcase |
s.toLowerCase()
|
map Data.Char.toLower s
|
s.downcase! |
|
|
s.each_byte {|x|
... } |
for(int i=0; i < s.length(); i++){
char x = s.charAt(i);
...
}
|
mapM_ (¥x->...) s
--
副作用を含む処理を順次起動するって意味では
mapM_で正解だけど、...のところはモナドじゃないといけない。
実際そこまでは要らなくて集計値とか計算結果のリストが欲しいだけで
foldシリーズやただのmapで十分ってことも多いと思われる。
|
//J2SE5.0より
for(char x:s.toCharArray()){
...
} |
s.each_line {|x|
... } |
String[] xs = s.split("¥n",-1);
for(int i=0 ; i < xs.length; i++){
String x = xs[i];
...
}
|
mapM_ (¥x->...) $ lines s |
//J2SE5.0より
for(String x:s.split("¥n",-1)){
...
} |
s.empty? |
s.length() == 0
|
null s
|
s.end_with?(x) |
s.endsWith(x)
|
Data.List.isSuffixOf x s
|
s.gsub(x, y) |
s.replaceAll(x, y)
|
|
s.gsub!(x, y) |
|
|
s.hex
s.to_i(16)
|
Integer.parseInt(s,16) |
|
s.include?(x) |
s.indexOf(x) >= 0
|
|
s.index(x) |
s.indexOf(x) |
|
s.insert(i, x) |
// sbはStringBuffer型
sb.insert(i,x);
|
|
s.length
s.size
|
s.length()
|
length s
|
s.ljust(x) |
|
|
s.lstrip |
|
dropWhile Data.Char.isSpace s
|
s.lstrip! |
|
|
s.match(x) |
s.matches(x)
|
|
x.match(s) |
java.util.regex.Pattern.matches(x, s)
|
|
s.next
s.succ |
|
|
s.next!
s.succ! |
|
|
s.oct
s.to_i(8)
|
Integer.parseInt(s,8) |
|
s.partition(x) |
|
Data.List.partition x s
|
s.replace(x) |
|
|
s.reverse |
|
reverse s
|
s.reverse! |
// sbはStringBuffer型
sb.reverse(); |
|
s.rindex(x) |
s.lastIndexOf(x)
|
|
s.rjust(x) |
|
|
s.rpartition(x) |
|
|
s.rstrip |
|
|
s.rstrip! |
|
|
s.scan(x) { ... } |
TODO
|
|
s[i]
s.slice(i)
|
s.charAt(i)
|
s !! i
|
s[i..-1]
s.slice(i..-1)
|
s.substring(i)
|
drop i s
|
s[i, l]
s.slice(i, l)
|
s.substring(i,i+l) |
take l $ drop i s
|
s[i..j]
s.slice(i..j)
|
s.substring(i,j+1)
|
take (l-i+1) $ drop i s |
s[i...j]
s.slice(i...j)
|
s.substring(i,j) |
take (l-i) $ drop i s |
s.split(x) |
s.split(x)
|
|
s.start_with?(x)*4 |
s.startsWith(x)
|
Data.List.isPrefixOf x s |
s.strip |
s.trim()
|
|
s.strip! |
|
|
s.sub(x, y) |
|
|
s.sub!(x, y) |
|
|
s.swapcase |
|
|
s.to_f |
Float.parseFloat(s)
|
read s
--この式が使用される場所の型によって適宜、変換関数の実装が(コンパイル時に)選択される(多相型)
|
s.to_i |
Integer.parseInt(s)
|
read s
--同上
|
s.tr!(x, y) |
|
|
s.tr_s!(x, y) |
|
|
s.unpack(x) |
|
|
s.upcase |
s.toUpperCase()
|
map Data.Char.toUpper s
|
s.upcase! |
|
|
Regexp.escape(s)
Regexp.quote(s)
|
|
|