文字列

文字列

Stringとそのスーパークラス、サブクラスを紹介。
配列と同じ項目もあり。
ただしモノによっては文字列での使用が禁止されているメソッドもある。
s := 'Hello'.
s1 := s addAll: ' World' >> 'This message is not appropriate for this object'

※Smalltalkの文字列では、破壊的に修正するようなコレクション共通メソッドは禁止されているようだ。

文字列の特徴:
  • リテラルで定義するとimmutableな状態になり、エラーになる処理がある。(インスペクタの画面ラベルが違うよね)
'Hello World' at: 1 put: $F >> NoModificationError
(WriteStream on: '') nextPut: $a >> NoModificationError
 beMutableとするとこれらの処理ができるようになる。

  • マルチバイト文字を含む文字列はTwoByteStringになる。
'Hello Worldあ' class
 このクラスになると、シングルバイトの文字を含む場合も全て2バイト計算になる。
 また、3バイト以上の文字は存在しない。

  • 全角文字=シングルバイト文字ではない
'×' class
 例えば乗算記号はビッグエンディアン側の数値(218)に割り当てられている。

文字列を作る
繰り返し文字列を生成する
文字から文字列にする
文字列の1文字目を取得する
文字列の最後の文字を取得する
文字列の指定した位置の文字を取得する
文字列の先頭から指定した文字数分を取得する
文字列の最後の指定した文字数分を取得する
指定した文字数を先頭から取り除く
指定した文字数を最後から取り除く
文字列のバイト数を取得する
マルチバイト文字が含まれるか調べる
文字列を結合する
大文字・小文字に揃える
シングルクォーテーションでくくる
文字列をひっくり返す
任意の位置から任意の位置まで文字列を切り出す
指定したオブジェクトの手前までを切り出す
文字列がある文字列で始まるか調べる
文字列中にある文字が含まれるか調べる
文字列中にある条件にマッチする文字が含まれるか調べる
文字列中のある文字の位置を先頭から探す
文字列中のある文字の位置を最後から探す
文字列中の文字がある条件にマッチする最初の位置を返す
文字列中の文字がある条件にマッチする最後の位置を返す
文字列中からある条件にマッチする最初の文字を取得する
文字列中からある条件にマッチする最初の文字を取得し、なければないなりの動作をする
文字列を検索する
文字列がパターンにマッチするか真偽を問う
マッチしたパターンの最初と最後の位置を捉えて何かする
文字列とパターンマッチさせる
文字列を置換する
改行ありの文字列にする
文字列を数値系のクラスに変換する
ファイルオブジェクトに変換する
両端の半角スペースを取り除く
左側に文字を詰めて指定した文字数にする
右側に文字を詰めて指定した文字数にする
両端の特定の文字を取り除く
左側の特定の文字を取り除く
右側の特定の文字を取り除く
指定した文字で区切る
条件にマッチする文字で区切る
条件にマッチする文字で区切りつつループもする
条件にマッチしない文字で区切る
条件にマッチしない文字で区切りつつループもする
文字の前後関係を見て区切る
両端から指定した数だけ文字列を切り出す
長い文字列は...を挟んで省略する
最初の文字以外の母音をなくす
後ろから母音を除いていく



'Hello'

まずはここから。


String new: 10 withAll: $a

単一文字から指定した数の文字列を作れるが、文字列を増幅して文字列を作る方法は基本的には用意されていない。


String with: $a
または
$a asSymbol asString

シンボルがStringのサブクラスなので、asSymbolまですれば事足りることが多い。


'Hello' first


'Hello' last

コレクション共通。


'Hello' at: 3

コレクション共通。


'Hello' first: 3

コレクション共通。


'Hello' last: 3

コレクション共通。


'Hello' allButFirst: 2

コレクション共通。値段で'\ 500'みたいな文字列を数値に変換するときとかに使えるのかな?思いつくのはそれくらい。


'Hello' allButLast: 1

コレクション共通。ファイルを読み込んで改行文字が最後に必ず入る場合とかに使えるかも。


'Hello' size

コレクション共通。シングルバイト(ByteStringクラス)ならこの一本槍でよい。
マルチバイト(TwoByteStringクラス)の場合もバイト数ではなく文字数が返る。


'こんにちは。' sizeInBytes

マルチバイト文字を含む文字列は基本的には文字数の2倍が返ってくる。


foo := 'AAAAAA'.
foo sizeInBytes = foo size

マルチバイト文字を含んでいれば数が異なるのでfalseになる。
asIntegerが256以上になる文字を含んでいる場合、自動的にTwoByteStringクラスのインスタンスになる。
'AAAAAA' isKindOf: TwoByteString
としてもよいかも。
ただし、これらのチェックには注意点あり。
1. 'AAA' asTwoByteString なんてやると、シングルバイト文字だけで構成されていてもTwoByteStringになる。
2. 元々TwoByteStringだった文字列のマルチバイト部分をシングルバイトに置き換えても、属するクラスはTwoByteStringのまま。
3.±×÷なんかは全角文字だけどシングルバイトである。
万全を期すなら (String with: foo) sizeInBytes = (String with: foo) size のよに文字列を作り直すのが良いのではないか。


'Hello', ' ', 'World'

コレクション共通。なのでその他のコレクション型クラスでもガンガン使うべし。


'Small Talk' asLowercase.
'Big Talk' asUppercase.

文字(Character)自体にasLowercase、asUppercaseが定義されていて、これを1文字ずつ繰り返している。


'Hello' printString

SQLをDBに渡すときは、文字列が同じくシングルクォーテーションくくりなのでこの仕様も使いどころがある。
だが、単に^selfして欲しいときがあるのもまた事実。


'Hello' reverse
コレクション共通。

'Hello' copyFrom: 2 to: 4

コレクション共通。でも文字列で使うことが一番多いのではと思う。


'Hello'  copyUpTo: $o

コレクション共通。長い文字列になるともう使えないだろうなぁ。


'Hello' beginsWith: 'Hel'

コレクション共通。といっても('Hello' first: 3) = 'Hel'とかやれば代用できるので登場する機会は少なそうだ。



'Hello World' includes: $o

コレクション共通。trueかfalseかだけ返す。位置まで知りたい場合はindexOf:を使う。



'Hello World。' contains: [:i | i isLetter and: [i isAlphabetic not]]

コレクション共通。条件をブロックで渡すところがincludes:と異なる。
ちなみにisLetterは半角アルファベットか全角文字に対しtrueとなるので、このブロックは全角文字が含まれていればtrue。


'Hello World' indexOf: $o

コレクション共通。ブロックで渡せるfindFirstの方がが汎用性が高い。



'Hello World' lastIndexOf: $o

コレクション共通。ブロックで渡せるfindLastの方が汎用性が高い。


'Hello World' findFirst: [:i | i = $o]

コレクション共通。文字単位で探したい場合。


'Hello World' findLast: [:i | i = $o]

コレクション共通。findFirstと対を成すメソッド。



'Hello World。' detect: [:i | i isLetter and: [i isAlphabetic not]]

コレクション共通。先頭からチェックしていくメソッドしか用意されていない。
また、見つからないとエラーになる。



'Hello World。' detect: [:i | i isLetter and: [i isAlphabetic not]] ifNone: [nil]

コレクション共通。先頭からチェックしていくメソッドしか用意されていない。
見つからない場合、ifNoneブロックの評価結果が返る。
あるかないかだけ判断したいならconteins:を使ったほうが便利。


'Hello World' findString: 'Wo' startingAt: 1

発展形でfindString:startingAt:ifAbsent:、findString:startingAt:ignoreCase:useWildcards:といった
タイプもある。


'H*o W##ld' match: 'Helllllo World'

発展形としてmatch:ignoreCase:もある。*は0文字以上にマッチ、#は1文字にマッチする。



| str |
str := 'Morning,Afternoon/Evening;Night'.
str matchesPattern: '*,*/*;*' ignoreCase: false do: [:st :ed | Transcript cr; show: (str copyFrom: st to: ed)]

こんなことをしたい日がいつか来るのか疑問だが、何か面白いことができた感じがする。


'Hello World' rangeOfPattern: 'H*W' startingAt: 1 ignoreCase: false

'*'で0文字以上にマッチ、'#'で1文字にマッチする。Rangeオブジェクトで返ってくる。
最短マッチしか行われない。



'Good morning' copyReplaceAll: 'morning' with: 'afternoon'

コレクション共通。開始終了位置を指定できるcopyReplaceFrom:to:with:というメソッドもある。


'Hello\World' withCRs

'\'そのものを残したい場合もあるかもしれないが、残念ながらエスケープする方法はない。
'Hello<n>World' expandMacros
という方法もある。expandMacrosの使用方法は本家のCincomのチュートリアルが詳しい。


'77.7s' asNumber

数字さえ入っていれば適当に数値系のクラスに変換してくれる。.があればFloatに、.があってsで終われば
FixedPointになる。数字がない場合は0が返る。

'C:\temp\foo.st' asFilename

STファイルのフルパスがコピペできるならファイルインも簡単。
'C:\xxx\yyy\zzz\bar.st' asFilename fileIn


' H e l l o W o r l d ' trimBlanks

できれば指定した文字を取り除けるメソッドが欲しかった。


((String new: 10 withAll: $0), 'Hello') last: 10

このテのことがしたい場合、文字数よりバイト数指定したい場合のほうが多いのではと思うが、
残念ながらマルチバイトが混じりつつ指定したバイト数に詰めるのは結構難しい。
とりあえずシングルバイトだけの場合に有効な方法を紹介。


('Hello', (String new: 10 withAll: $0)) first: 10

左詰めを逆方向にしただけ。

((('-----Hello - World-----' copyReplaceAll: ' ' with: 0 asCharacter asSymbol) copyReplaceAll: '-' with: ' ') 
    trimBlanks copyReplaceAll: ' ' with: '-') copyReplaceAll: 0 asCharacter asSymbol with: ' ' >>  'Hello - World'

(1)半角スペースをNULL文字へ退避させ、(2)ハイフンを半角スペースに置き換え、(3)その半角スペースを取り除く。
(4)残った半角スペースをハイフンに戻し、(5)NULL文字を半角スペースに戻せばよい。
でもターゲットの文字列を変数に入れて、
foo copyFrom: (foo findFirst: [:i| i ~= $-]) to: (foo findLast: [:i | i ~= $-])
としたほうが楽。


((((('-----Hello - World-----', 0 asCharacter asSymbol) copyReplaceAll: ' ' with: 0 asCharacter asSymbol)  copyReplaceAll: '-' with: ' ') 
    trimBlanks copyReplaceAll: ' ' with: '-') copyReplaceAll: 0 asCharacter asSymbol with: ' ') allButLast: 1 >> 'Hello - World----'

両端の特定の文字を取り除く方法の最初にNULL文字付加する処理、最後に取り除く処理を追加。
でもターゲットの文字列を変数に入れて、
 foo copyFrom: (foo findFirst: [:i| i ~= $-]) to: foo size
としたほうが楽。


(((((0 asCharacter asSymbol, '-----Hello - World-----') copyReplaceAll: ' ' with: 0 asCharacter asSymbol)  copyReplaceAll: '-' with: ' ') 
    trimBlanks copyReplaceAll: ' ' with: '-') copyReplaceAll: 0 asCharacter asSymbol with: ' ') allButFirst: 1 >> '-----Hello - World'
左側バージョンと基本的に同じ。NULL文字付加する場所が最初か最後かの違い。
でもターゲットの文字列を変数に入れて、
foo copyFrom: 1 to: (foo findLast: [:i| i ~= $-])
としたほうが楽。


'Morning,Afternoon,Evening' tokensBasedOn: $,

コレクション共通。でも文字列で使うことが多いと思う。



'Morning,Afternoon/Evening;Night' runsFailing: [:i | #($, $/ $;) includes: i]

コレクション共通。マッチする文字が続く場合、まとめて一区切りとする。tokensBasedOn:だけで十分な気もする。



'Morning,Afternoon/Evening;Night' runsFailing: [:i | #($, $/ $;) includes: i] do: [:i | Transcript cr; show: i]

コレクション共通。マッチする文字が続く場合、まとめて一区切りとする。tokensBasedOn:とdo:で十分な気もする。



'123,456,789.321' runsSatisfying: [:i | i isDigit]

コレクション共通。runsFailing:の逆条件バージョン。マッチする文字が続く場合、まとめて一区切りとする。



'123,456,789.321' runsSatisfying: [:i | i isDigit] do: [:i | Transcript cr; show: i]

コレクション共通。runsFailing:do:の逆条件バージョン。マッチする文字が続く場合、まとめて一区切りとする。



'getFieldKnownNotToBeAName:' piecesCutWhere: [:i :j | i isLowercase and: [j isUppercase]]

コレクション共通。これはキャメルケースを単語ごとにカットした場合。
tokensBasedOnやrunsXxxing:は区切り文字が残らないが、これは残る。また、1文字の条件でも区切ることができる。
/**/型のコメントをより分けることも可能。

('DECLARE
    dt DATE; /*変数定義*/
BEGIN
    /*今日の日付をdtに格納*/
    SELECT SYSDATE
    INTO dt
    FROM DUAL;
    /*標準出力させる*/
    /*DBMS_OUTPUT.PUT_LINE(dt);/*''YYYY-MM-DD''*/
    DBMS_OUTPUT.PUT_LINE(TO_CHAR(dt, ''YYYY/MM/DD''));
EXCEPTION
    WHEN OTHERS THEN
        /*例外処理*/
        DBMS_OUTPUT.PUT_LINE(SQLERRM)
END;
/'
    piecesCutWhere: [:i :j | ((i = $/) & (j = $*)) | ((i = $*) & (j = $/))])
    groupedBy: [:i | i first = $*]


s := 'Hello' chopTo: 4

何故か両端から切り出す。何に使うんだろう?


s := 'Hello World' contractTo: 2

さっぱり使いどころがわからない。。。

s := 'Hello World' dropFinalVowels

さっぱり使いどころがわからない。。。

s := 'Hello World' dropVowels: 5

後ろから母音を除いていくが、母音の数が引数より少ない場合、今度は何でもいいから
前から文字を削り始める。
さっぱり使いどころがわからない。

  • ぐっじょぶ(´-ω-)♪ http://www.l7i7.com/ -- にゃん (2012-03-05 12:36:54)
  • プレイ内容:自由。時間:自由。場所:自由。男性アルバイト募集中( ●≧艸≦) ♪ http://b8y.in/ -- 珠緒 (2012-07-01 00:34:48)
名前:
コメント:
-

タグ:

+ タグ編集
  • タグ:
最終更新:2012年07月01日 00:34
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。