2006年10月22日

文字列操作の比較表: Ruby, Python, JavaScript, Perl, C++

Ruby, Python, JavaScript, Perl, C++ の文字列操作の比較表を作りました。配列操作の比較表の続編です。間違いなどがあったらご指摘いただけると助かります。

   
Ruby (String) Python (str) JavaScript (String) Perl C++ (std::string)
s = "abc" s = "abc" s = "abc" $s = "abc" string s = "abc"
s = x + y s = x + y s = x + y $s = $x . $y s = x + y*1
s == x s == x s == x $s eq $x s == x
s % [x, y]
sprintf(s, x, y)
s % (x, y) sprintf(s, x, y) format(s) % x % y*3
[x, y, z].join(s) s.join([x, y, z]) [x, y, z].join(s) join(s, x, y, z) vector <string>
...
join(v, s)*5
s.capitalize s.capitalize() ucfirst($s)
s.capitalize!
s.center(x) s.center(x)
s.chomp s.rstrip("\n")
s.chomp! chomp($s)
s.chop s[0:-1]
s[:-1]
s.chop! chop($s) s.erase(s.size() - 1, 1)*2
s.clear s.clear()
s.concat(x) $s .= $x s.append(x)
s.count(x) $s =~ tr/$x//
s.crypt(x) crypt.crypt(s, x) crypt($s, $x)
s.delete!(x) $s =~ tr/$x//d
s.downcase s.lower() s.toLowerCase() lc($s) to_lower_copy(s)*3
s.downcase! to_lower(s)*3
s.each_byte {|x| ... } for x in s:
  ...
for (i in s) {
  x = s[i];
  ...
}
for $x (map ord, split //, $s) { ... } for (int i = 0; i < s.size(); ++i) {
  char x = s[i];
  ...
}
s.each_line {|x| ... }*6 for x in s.splitlines()
  ...*6
for $x (split /\n/, $s) { ...}*6 istringstream is(s);
while (getline(is, x)) {
  ...*6
}
s.empty? s == ""
not s
s == "" $s eq "" s.empty()
s.end_with?(x)*4 s.endswith(x) ends_with(s, x)*3
s.gsub(x, y) re.sub(x, y, s) s.replace(/x/g, y) replace_all_regex_copy(s, x, y)*3
s.gsub!(x, y) $s =~ s/$x/$y/g replace_all_regex(s, x, y)*3
s.hex
s.to_i(16)
int(s, 16) parseInt(s, 16) hex($s) int i;
istringstream(s) >> hex >> i;
s.include?(x) x in s s.indexOf(x) != -1 index($s, $x) != -1 s.find(x) != sting::npos
contains(s, x)*3
s.index(x) s.index(x)
s.find(x)
s.indexOf(x) index($s, $x) s.find(x)
s.insert(i, x) substr($s, $i, 0, $x)
substr($s, $i, 0) = $x
s.insert(i, x)
s.length
s.size
len(s) s.length length($s) s.size()
s.ljust(x) s.ljust(x)
s.lstrip s.lstrip() trim_left_copy(s)*3
s.lstrip! $s =~ s/^\s+// trim_left(s)*3
s.match(x)
x.match(s)
re.search(x ,s) s.match(x) $s =~ /$x/ regex_match(s, x)*3
s.next!
s.succ!
$s++
s.oct
s.to_i(8)
int(s, 8) parseInt(s, 8) oct($s) int i;
istringstream(s) >> oct >> i;
s.partition(x)*4 s.partition(x)
s.replace(x) s.assign(x)
s.reverse s[::-1] reverse($s) string(s.rbegin(), s.rend())
s.reverse! reverse(s.begin(), s.end())
s.rindex(x) s.rindex(x)
s.rfind(x)
s.lastIndexOf(x) rindex($s, $x) s.rfind(x)
s.rjust(x) s.rjust(x) sprintf("%*s", $x, $s)
s.rpartition(x)*4 s.rpartition(x)
s.rstrip s.rstrip() trim_right_copy(s)*3
s.rstrip! $s =~ s/\s+$// trim_right(s)*3
s.scan(x) { ... } while ($s =~ m/$x/g) { ... }
s[i]
s.slice(i)
s[i] s.charCodeAt(i) ord(substr($s, $i, 1)) s[i]
s[i..-1]
s.slice(i..-1)
s[i : ] s.substr(i) substr($s, $i) s.substr(i)
s[i, l]
s.slice(i, l)
s[i : i + l] s.substr(i, l) substr($s, $i, $l) s.substr(i, l)
s[i..j]
s.slice(i..j)
s[i : j + 1] s.slice(i, j + 1) substr($s, $i, $j - $i + 1) s.substr(i, j - i + 1)
s[i...j]
s.slice(i...j)
s[i : j] s.slice(i, j) substr($s, $i, $j - $i) s.substr(i, j - i)
s.split(x) s.split(x) s.split(x) split($x, $s) vector<string> l;
split(l, s, is_any_of(x))
// or...
split_regex(l, s, x)*3
s.start_with?(x)*4 s.startswith(x) starts_with(s, x)*3
s.strip s.strip()
s.strip! $s =~ s/(^\s+|\s+$)// trim(s)*3
s.sub(x, y) re.sub(x, y, s, 1) s.replace(/x/, y) replace_regex_copy(s, x, y)*3
s.sub!(x, y) $s =~ s/$x/$y/ replace_regex(s, x, y)*3
s.swapcase s.swapcase()
s.to_f float(s) parseFloat(s) float f;
istringstream(s) >> f;
// or...
lexical_cast<float>(s) *3
s.to_i int(i) parseInt(s) int($s) int i;
istringstream(s) >> i
// or...
lexical_cast<int>(s) *3
s.to_s str(s) s.toString() string(s)
s.tr!(x, y) $s =~ tr/$x/$y/
s.tr_s!(x, y) $s =~ tr/$x/$y/s
s.unpack(x) struct.unpack(x) unpack($x, $s)
s.upcase s.upper() s.toUpperCase() uc($s) to_upper_copy(s)*3
s.upcase! to_upper(s)*3
Regexp.escape(s)
Regexp.quote(s)
re.escape(s) quotemeta(s)
  1. string s = "abc" + "def" はコンパイルエラーです。C++ の文字列リテラルは string オブジェクトではないためです。 string s = string("abc") + "def" で回避できます。
  2. 長さが 0 のときの動作は未定義です。
  3. Boost を使用。boost や boost::algorithm などの名前空間は省略しました。
  4. Ruby 1.9 から導入されました
  5. Boost の開発版にあります。
  6. Ruby の each_line は行ごとに改行コードが残りますが、その他の言語の例では残りません。

補足

表の作成にあたって、一番慣れている Ruby を基準にしました。 Ruby 以外の言語に同等のものが見当たらなかった以下のメソッドは省略しました。

s.casecmp(x), s.delete(x), s.dump, s.intern/s.to_sym, s.next/s.succ, s.slice!, s.squeeze, s.squeeze!, s.sum, s.swapcase!, s.tr(x, y), s.tr_s(x, y), s.upto

ほかの言語に存在して (今のところ) Ruby に存在しないものでは Python の s.expandtabs が便利だと思います。

Python と JavaScript には文字列を破壊的に変更する操作はないようです。

謝辞

以下の方々から間違いの指摘や改良案などのコメントをもらいました。ありがとうございます。

他の言語

表の作成について

以前に配列操作の比較表:を作成したときはテキストエディタでちまちまと編集しましたが、今回は OpenOffice.org の Calc という表計算ソフトを使って編集しました。表の編集はやはり表計算ソフトの方がだんぜん楽でした。

編集にあたっては、メニューの「ツール→オートコレクト」の「オプション」の「すべての文を大文字から始める」と「印刷用クォーテンションマーク」の「ダブルクォーテンションの置換」をオフにしました。セル内で改行を入力するには Excel の Shift+Enter ではなく Ctrl+Enter だったのに一瞬つまづきました。

HTML の生成は、表をTAB区切りの CSV形式で保存したファイルに対して、次のようなスクリプトを適用して行いました。

require 'webrick'
content = STDIN.read
line_num = 0
lines = content.split("\r\n")
lines.each {|line|
  line_num += 1
  puts "<tr>"
  columns = line.split("\t")
  columns.each {|column|
    elem = (if line_num == 1 then "th" else "td" end)
    column.sub!(/\A"(.*)"\Z/m, "\\1")  # Trim leading/trailing quotes.
    column.gsub!(/""/, '"')  # Replace "" with ".
    column = WEBrick::HTMLUtils.escape(column)
    column.gsub!(/  /, "&nbsp;&nbsp;")   # Preserve indentation.
    column.gsub!(/\n/, "<br />\n")
    column = "" if column == "-"

    if column.empty?
      printf("<%s class=\"empty\">", elem)
    else
      printf("<%s>", elem)
    end
    print column
    printf("</%s>\n", elem)
  }
  print "</tr>\n\n"
}