Ruby との文字列操作の比較
毎度お呼びでないことは重々承知の助なのですが…(^_^;)。前回同様、いやなブログ: 文字列操作の比較表: Ruby, Python, JavaScript, Perl, C++ に便乗して、Squeak の Smalltalk における文字列操作の紹介をさせてください。
Ruby (String) |
Squeak の Smalltalk (String) |
備 考 |
---|---|---|
s = "abc" | s = 'abc' | シングルクオーテーションのみ |
s = x + y | s = x, y | カンマを使用 |
s == x | s = x | |
s sameAs: x | 大文字小文字を区別せず比較 | |
s howManyMatch: x | 合致している文字数を返す | |
s charactersExactlyMatching: x | ||
s.casecmp(x) | (s compare: x) - 2 | |
s % [x, y] | s format: {x. y} | 単純な置き換えのみ |
sprintf(s, x, y) | ||
[x, y, z].join(s) | ||
s.capitalize | s capitalized | |
s.center(x) | ||
s contractTo: n | 途中を...で省略 | |
s.chomp | s withoutTrailingBlanks | ただし空白等も削除 |
s.chop | s allButFirst | |
s allButFirst: n | ||
s.clear | (s copyEmpty) | 非破壊版のみ |
s.concat(x) | ||
s.count(x) | s occurrencesOf: x | |
s.crypt(x) | ||
s.delete(x) | s copyWithoutAll: x | |
s.downcase | s lowercase | |
s.downcase! | s translateToLowercase | |
s.each_byte {|x|...} | s do: [:x|...] | |
s.each_line {|x|...} | s linesDo: [:x|...] | |
s lineCount | 行数のカウント | |
s lineNumber: n | n行目の行文字列 | |
s lineCorrespondingToIndex: n | n文字目が含まれる行文字列 | |
s.empty? | s isEmpty | |
s.end_with(x) | s endsWith: x | |
s endsWithAnyOf: {x. y. z} | 複数候補用 | |
s endsWithDigit | 数字で終わっているか | |
s.hex s.to_i(16) |
(Number readFrom: s base: 16) | |
s.include?(x) | s includes: x | 文字の場合 |
s includesSubString: x | 文字列の場合 | |
s.index(x) | s indexOf: x | 文字の場合 |
s findString: x | 文字列の場合 | |
s findAnySubStr: {x. y. z} startingAt: 0 | 複数候補の文字列の場合 | |
s.insert(i, x) | ||
s.size s.length |
s size | |
s.ljust(x) | s padded: #right to: x with: $* | 第二引数で文字を指定 |
s.lstrip | s withoutLeadingDigits | ただし数字も削除 |
s.next! s.succ! |
||
s.oct s.to_i(8) |
(Number readFrom: s base: 8) | ('8r', s) asNumberでも同じ |
s.partition(x) | ||
s splitInteger | '123abc' => #(123 'abc') | |
s.replace(x) | (s become: x copy) | |
s.reverse | s reversed | |
s.rindex(x) | s lastIndexOf: x | 文字の場合 |
s findLastOccuranceOfString: x startingAt: 1 | 文字列の場合 | |
s lastSpacePosition | 空白の場合 | |
s.rjust(n) | s padded: #left to: n with: $* | 第二引数で文字を指定 |
s truncateTo: n | n文字以下になるように | |
s withNoLineLongerThan: n | n文字ごとに改行挿入 | |
s truncateWithElipsisTo: n | n文字以下になるように...で省略 | |
s.rpartition(x) | ||
s stemAndNumericSuffix | 'abc123' => #('abc' 123) | |
s.rstrip | s withoutTrailingBlanks | ただし数字も削除 |
s[i] | s at: i | ただし開始インデックスは1 |
s[i..-1] | s allButFirst: i | |
s[i, l] | (s copyFrom: i to: i+l-1) | |
s[i..j] | s copyFrom: i to: j | |
s[i...j] | (s copyFrom: i to: j-1) | |
s.split(x) | s subStrings | 区切りは空白等で固定 |
s splitOnCapBoundaries | 'aBcDef' => #('a' 'bc' 'def') 3.9 では不可 |
|
s keywords | #at:put: => #('at:' 'put:') | |
s subStrings: {x. y. z} | パターン指定不可。文字で区切る場合 | |
s findTokens: {x. y. z} | 上に同じ。 | |
s findBetweenSubStrs: {x. y. z} | パターン指定不可。文字列で区切る場合 | |
s.sqeeze | ||
s withSeparatorsCompacted | 空白等のみ重複解消 | |
s withBlanksCondensed | 同上。ただし頭尾の空白等は削除 | |
s.start_with(x) | s beginsWith: x | |
s startsWithDigit | 数字で始まるか | |
s.strip | s withBlanksTrimmed | |
s.swapcase | ||
s.to_f | (Float readFrom: s) | |
s.to_i | s initialIntegerOrNil | ただし解釈不可のときnil |
s asSignedInteger | 文字列途中からでも可 | |
s asUnsignedInteger | 同上、符号を無視する場合 | |
s numericSuffix | 末尾から解釈 | |
s extractNumber | 文字を無視して解釈 'a1b2' => 12 | |
(s onlyLetters) | (おまけ:上の逆操作 'a1b2' => 'ab') | |
s romanNumber | ローマ数字として解釈 'XXXVII' => 37 | |
s.to_sym | s asSymbol | |
s asCharacter | ただし最初の1文字のみ(s firstと同じ) | |
s asTime | 比較的自由な書式で | |
s asDate | 比較的自由な書式で | |
s asDataAndTime | 0000-00-00T00:00:00+00:00形式のみ | |
s.tr(x, y) | s copyReplaceAll: x with: y | 範囲指定不可 |
s withCRs | 文字列中の\を改行に置換 | |
s copyReplaceTokens: {x} with: y | 範囲指定不可。複数候補の文字列用 | |
s.tr!(x, y) | s replaceAll: x with: y | 範囲指定不可。文字用 |
s.tr_s(x, y) | ||
s.unpack(x) | ||
s.upcase | s uppercase | |
s.upcase! | s translateToUppercase | |
イディオム
#streamContents: を使うと、規則性を持つ文字列を生成する際に便利です。たとえば、Smalltalk には Ruby の join みたいなのは用意されていませんが、代わりに(…と自慢げに言うほどシンプルではないのですが(^_^;))この #streamContents: と #do:separatedBy: とを併用してこんなふうに書けます。| array | array := #('abc' 'def' 'ghi'). String streamContents: [:ss | array do: [:str | ss nextPutAll: str] separatedBy: [ss nextPut: $:]]
=> 'abc:def:ghi'
変わった機能
スルー癖がついてしまうと、普段なかなか String のメソッドなんてじっくり見ようとは思わないので、こういうふうに整理しているといろいろと発見があって面白いです。以下、リストに居場所がなかった処理たちについて。文字列を数値に見立てての演算
Smalltalk も -76 くらいまでは Ruby とかと同様にプラスを使っていたのですが、ダブルディスパッチとかが流行り始めてから(おそらく…)プラスは演算に使って文字列の結合にはカンマを使うようになりました。アスタリスクもしかりです。'23' + '4' " => '27' " '23' - '4' " => '19' " '23' * '4' " => '92' " '23' / '4' " => '(23/4)' " '23' // '4' " => '5' " '23' \\ '4' " => '3' "
パターンマッチング
前述のとおり、正規表現はライブラリ頼みなのですが、ごく基本的なパターンマッチもどきはデフォでも使えるみたいです。ファイルリストで項目をしぼるときの機構がたしかコレだったはず。'a#c*' match: 'abc123' " => true "タブとかスペースとかでデリミタを決めうちして何かをする…というタイプの処理はいろいろあるみたいです。上の表には似たような用途のものは無理矢理押し込んでしてしまいました。他にも、カラム処理などを意識したのか、こんなのを見つけました。
'abc def ghi' tabDelimitedFieldsDo: [:each | Transcript cr; show: each]
'abc def ghi' do: [:each | Transcript cr; show: each] toFieldNumber: 2文字列中の空白はタブです。タブで区切られた文字列を抽出して各項目について(あるいは後者ではさらに指定したものに限って)ブロックで与えられた処理をするようです。
環境や、アプリ、GUI 向けの裏方
アプリケーションでも組むのでもなければあまり使い出はなさそうですが、いろいろとあります。 括弧の対応を調べる。'((())())' findCloseParenthesisFor: 2 " => 5 "インデント(タブ)の深さを測る。
' abc' indentationIfBlank: [0] " => 1 '式からセレクタを抽出する。
's at: 1 put: $A' findSelector " => #at:put: "ファイル名に見立てて、ファイル名のみを抽出。
'abc.txt' sansPeriodSuffix " => 'abc' "改行表現の変換。
s withInternetLineEndings " CR を CRLF に " s withSqueakLineEndings " LF, CRLF を CR に "スペルチェックの候補。
'abc' correctAgainst: Symbol allSymbols " => an OrderedCollection(#abc #Arc #abs #Atom #a42 #A2 #a5f #a13: #arrowSpec #abstractAModel) "ネット系の(多国語がらみでない)エンコード関係。そうそう。今回は多国語関連は省きました。ごめんなさい。
'<br>' encodeForHTTP " => '%3Cbr%3E' " '%3Cbr%3E' unescapePercents " => '<br>' " '<>' asHtml " => '<>' " '<>' replaceHtmlCharRefs " => '<>' " '[AB\C]' asIRCLowercase " => '{ab|c}' "括弧でくくる、括弧を外す。
'''abc''' withoutQuoting " => 'abc' " 'abc' surroundedBySingleQuotes " => '''abc''' " 'abc' asSmalltalkComment " => '"abc"' " '(abc)' unparenthetically " => 'abc' "