概要

Scalaの文字列は、基本的にはjava.lang.Stringを利用している。

但し、PredefでStringOpsへの暗黙の型変換が定義されているので、StringOpsの関数も利用できる。StringOpsはStringLikeを継承している。

また、StringOpsとStringLikeは、scala.collection.immutableパッケージの中(ListとかMapがいるとこ)に入っており、StringLikeはcollectionが持つようないくつかのクラスを継承している。

そのため、collect、distinct、countなどのListなどでお馴染みの関数が利用可能だったり、foreachやforループが使えるなど、文字列に対してCollection的な扱いができるようになっている。

お陰でやたらとたくさんの関数が利用できるようになってるけど、Collection的なものの一部は明らかにStringでは使えないだろ的なものも混ざっているような気がする。

java.lang.StringのJavadoc
http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/String.html

StringOpsのScaladoc
http://www.scala-lang.org/api/current/scala/collection/immutable/StringOps.html

@CretedDate 2011/05/05
@Versions Scala2.8

*

文字列の繰り返しを得る。内部的にはStringBuilderで指定回数分連結している。

scala> "abc" * 3
String = abcabcabc

( )    charAt

括弧で指定インデックスのCharを取り出せる。これは動作的にはStringのcharAtと同じになる。

scala> "ABCDE"(2)
Char = C

scala> "ABCDE".charAt(2)
Char = C

// 範囲外のインデックスを指定した場合は、どちらも例外になる。
scala> "ABCDE"(10)       
java.lang.StringIndexOutOfBoundsException: String index out of range: 10

<    >

大なり小なりで比較できる。

scala> "abc" > "def"
Boolean = false

scala> "abc" < "def"
Boolean = true

「<=」や「>=」も利用可能。

addString

引数で渡されたStringBuilderに、文字列を追加する。

scala> val builder = new StringBuilder()
scala> "abc" addString builder
StringBuilder = StringBuilder(a, b, c)

引数に開始文字列、区切り文字、終了文字列なども指定できるらしい。

scala> ( "abc" addString(builder, "[", ",", "]") ) toString
java.lang.String = [a,b,c]

capitalize

文字列の先頭を大文字にする。先頭が英字でなければそのままの値を返す。

scala> "mac" capitalize
String = Mac

全体を大文字に、もしくは全体を小文字にする場合は、java.lang.StringのtoUpperCaseや.toLowerCaseを利用する。

collect

1文字ずつcase文で処理できる。

// AとCだけ大文字に変換する
scala> "mac" collect { case 'a' => 'A'; case 'c' => 'C'; case x => x }
 String = mAC

compare / compareTo

文字列を比較する。compareはStringLikeで実装されているが、中身はjava.lang.StringのcompareToを呼び出しているだけ。

scala> "linux" compare "windows"
Int = -11

scala> "linux" compareTo "windows"
Int = -11

contains

java.lang.Stringの機能。引数で渡した文字列が含まれる場合はtrue。

scala> "windows" contains "dow"  
Boolean = true

count

指定した条件が当てはまる文字をカウント。

// 「w」の出現回数をカウント
scala> "windows" count { _ == 'w' }
Int = 2

// アルファベット大文字の数をカウント
scala> "AbcDeF" count { c => c >= 'A' && c <= 'Z' }
Int = 3

diff

差分を出す。対象となるのは左辺のみ。たとえば「abc」と「bcd」のdiffは、「abc」の中で右辺に含まれてない文字=「a」になる。右辺の中で左辺と一致しない「d」は抽出されない。

scala> "abc" diff "bcd"
String = a

scala> "aabbcc" diff "abbc"
String = ac

distinct

文字の重複を省く。

scala> "ABCABDACBADB" distinct
String = ABCD

drop

先頭から指定した文字だけ落とす。

scala> "Windows" drop 3     
String = dows

dropRight

右側から指定した文字だけ落とす。

scala> "Windows" dropRight 3
String = Wind

dropWhile

条件に合致している間、文字をdropする。

// 「d」が出現するまでdrop
scala> "Windows" dropWhile {_ != 'd'}
String = dows

endsWith

java.lang.Stringの機能。末尾が指定した文字列で終わっているか。

scala> "linux" endsWith "ux"
Boolean = true

scala> "linux" endsWith "ws"
Boolean = false

equals / equalsIgnoreCase

両方ともjava.lang.Stringの機能。equalsは==と同様の挙動になる。equalsIgnoreCaseは名前の通り、大文字小文字を無視する。

scala> "linux" equals "LINUX"
Boolean = false

scala> "linux" equalsIgnoreCase "LINUX"
Boolean = true

exists

指定した条件に当てはまる文字が存在するか。

// 文字列の中に「x」が存在するかチェック
scala> "linux" exists {_ == 'x'}
Boolean = true

filter / filterNot

filterは指定した条件に当てはまらない文字を落とす。filterNotはその逆。

// 大文字小文字を無視して、A〜F以外は落とす
scala> "Alphabet" filter {c => c.toUpper  >= 'A' && c.toUpper <= 'F'}
String = Aabe

// 逆にA〜Fを落とす
scala> "Alphabet" filterNot {c => c.toUpper  >= 'A' && c.toUpper <= 'F'} 
String = lpht

find / findIndexOf

指定した条件に当てはまる文字を見つける。結果は、findは最初に見つけた文字(Option型)、findIndexOfは最初に見つけた文字の場所をIntで返す。

// Kより小さい最初の文字
"windows" find (_.toUpper < 'K')
Option[Char] = Some(i)

// findIndexOfは「i」の場所(1)を返す
scala> "windows" findIndexOf (_.toUpper < 'K')
Int = 1

forall

すべての文字に対して条件が当てはまればtrue、1文字でも条件外の文字があればfalse。

// 全文字が数値かチェック
scala> "1024" forall { _.isDigit }
Boolean = true

// 数値以外の文字が入っていたらfalse
scala> "10.5" forall { _.isDigit }   
Boolean = false

foreach

すべての文字に対して処理を実行。

// 1文字ずつずらして表示してみる
scala> "windows" foreach { c => print( ( c + 1 ).toChar ) }

// 余談だけどfor式も使える
scala> for( c <- "windows" ) print(c.toUpper)  
WINDOWS

format / formatLocal

Cのprintfに似たフォーマットを利用できる。内部的にはjava.lang.Stringのformatを利用。

scala> "%d/%d/%d(%s)" format (2011, 5, 5, "Thu")
String = 2011/5/5(Thu)

formatLocalは第一引数にLocaleを取る。これも動作はjava.lang.Stringのformatと同じ。

scala> val cal = java.util.Calendar.getInstance

scala> "%tA" formatLocal (java.util.Locale.US, cal)
String = Thursday

scala> "%tA" formatLocal (java.util.Locale.JAPAN, cal)
String = 木曜日

フォーマット文字列の詳細はjava.util.Formatter参照。
http://java.sun.com/javase/ja/6/docs/ja/api/java/util/Formatter.html

groupBy

グループ分けしたMapを返す。

// 大文字小文字問わず、同じ文字でグループ分けしてみる
scala> "ABbCcc" groupBy (x => x.toLower)
scala.collection.immutable.Map[Char,String] = Map((a,A), (c,Ccc), (b,Bb))

grouped

指定文字数で分割したiteratorを返す

// 3文字区切り
( "windows" grouped 3 ) foreach(println)
win
dow
s

head / headOption

先頭の文字を取得する。

scala> "linux" head
Char = l

// 空文字に実行すると例外
scala> "" head     
java.util.NoSuchElementException

// headOptionなら、空文字でも例外が起きずにOption型で返る
scala> "" headOption
Option[Char] = None

// 文字がある場合はもちろんSome(文字)が返る
scala> "linux" headOption
Option[Char] = Some(l)

indexOf / indexWhere

indexOfは指定したCharが最初に出現する場所を返す。indexWhereは条件に当てはまる最初の文字の場所を返す。

// 最初に出てくる「d」の場所
scala> "windows" indexOf 'd'
Int = 3

// 3文字目以降の「w」の場所
scala> "windows" indexOf('w', 3)
Int = 5

// 存在しない場合は-1
scala> "windows" indexOf 'l'
Int = 5

// indexWhereで、「f」より小さい最初の文字を指定
scala> "windows" indexWhere( _ < 'f' )
res177: Int = 3

// 3文字目以降で「o」より大きい最初の文字を指定
scala> "windows" indexWhere( _ > 'o', 3 )
res178: Int = 5

indices

文字数に応じたRangeを返す。

scala> "linux" indices
scala.collection.immutable.Range = Range(0, 1, 2, 3, 4)

init

最後の1文字を除いた文字列を返す。

scala> "linux" init
String = linu

intersect

diffの逆。一致する部分だけ返す。

scala> "aabbccdd" intersect "cdef"
String = cd

isDefinedAt

指定したindexが存在するかチェックする。内部的にやってることは「(idx >= 0) && (idx < length)」。

// 3文字目は存在するからtrue
scala> "linux" isDefinedAt 3
Boolean = true

// 10文字目は存在しないからfalse
scala> "linux" isDefinedAt 10
Boolean = false

isEmpty / nonEmpty

中身が空じゃないかチェックする。

// 空文字ならtrue
scala> "" isEmpty
Boolean = true

// nullだとお馴染みの例外
scala> (null: String) isEmpty
java.lang.NullPointerException

// 逆の結果を返すnonEmptyもある
scala> "" nonEmpty
Boolean = false

iterator

Iterator[Char]を取得する。Scalaの文字列はItrableLikeを継承してる。

scala> "linux" iterator
Iterator[Char] = non-empty iterator

last / lastOption

最後の文字を取得する。

scala> "linux" last
Char = x

// 空文字に実行すると例外
scala> "" last     
java.util.NoSuchElementException

// OptionでラップするlastOptionを使えば安全
scala> "" lastOption
Option[Char] = None

lastIndexOf / lastIndexWhere

後方から検索する以外はindexOfと同じ。

// 最後に出てくる「w」の位置
scala> "windows" lastIndexOf 'w'
Int = 5

// 最後に出てくる「o」より小さい文字の位置
scala> "windows" lastIndexWhere(_ < 'o')  
Int = 3

length

文字数を返す。sizeも同じ。

scala> "linux" size
Int = 5

lengthCompare

引数で指定した数値とlengthとの差を出す。

scala> "linux" lengthCompare 3
Int = 2

scala> "linux" lengthCompare 5
Int = 0

scala> "linux" lengthCompare 7
Int = -2

lines / linesIterator / linesWithSeparators

文字列を改行で区切ってIteratorを返す。linesとlinesIteratorは同じ処理をしているように見える。

linesとlinesIteratorは、区切った改行を取り去る。linesWithSeparatorsは改行を残す。

// 改行で区切る
scala> ( "one\ntwo\nthree" lines ) foreach println
one
two
three

// linesWithSeparatorsだと、改行が残っている
scala> ( "one\ntwo\nthree" linesWithSeparators ) foreach println
one

two

three

map

Listなどで利用されるあのmap。Collectionを回して処理を加え、新しいCollectionを生成する。

// 文字を1文字ずつずらした文字列を作成する
scala> "windows" map { c => (c + 1).toChar }
String = xjoepxt

// 大文字は小文字に、小文字は大文字に変換する
scala> "Windows" map( c => if(c.isUpper) c.toLower else c.toUpper )  
String = wINDOWS

matches

java.lang.Stringの機能。正規表現に適合するかをチェックする。

scala> "linux" matches "[a-z]+"
Boolean = true

max / min

文字コード的に最大、最小の文字を抽出する。

scala> "Linux" max                                               
Char = x

// 大文字の方が小文字よりコード的に小さいので、「L」が最小になる
scala> "Linux" min
Char = L

// 大文字小文字を無視するOrderを作ってみる
scala> val order = new Ordering[Char]() {
     |   def compare(x: Char, y: Char) = x.toLower compare y.toLower
     | }

// 上記のOrderingを引数に指定すると、「i」が最小になる
scala> "Linux" min order
Char = i

mkString

Listとかで連結して文字列を作りたい時に使うmkString。Stringクラスで使うことはあまりないと思われる。

// そのまま指定しても意味なし
scala> "Mac" mkString
String = Mac

// seqを指定して分割された感じにしてみる
scala> "Mac" mkString " | "
String = M | a | c

// 前と後ろに括弧を入れてみる
scala> "Mac" mkString("(", "", ")")
String = (Mac)

padTo

指定された文字数まで、指定文字で穴埋めする。

scala> "Mac" padTo (6, '_')                                
String = Mac___

partition

指定した条件で文字列を分ける。戻り値はTuple2の(String, String)。

// 大文字と小文字で分けてみる
scala> "AaBbCc" partition( _.isUpper )
(String, String) = (ABC,abc)

patch

パッチを当てる。

// 一番最初の文字を「L」に書き換える
scala> "Windows" patch(0, "L", 1)
String = Lindows

// 一番最初の2文字を「LinLi」に書き換える
scala> "Windows" patch(0, "LinLi", 2)
String = LinLindows

// 2文字目からの2文字を伏字にする
scala> "Fuck" patch(2, "xx", 2)    
res24: String = Fuxx

prefixLength

前方から条件に一致しない文字が出るまでカウントする。

// スペースが出てる間、カウント
scala> "   Test" prefixLength(_ == ' ')
Int = 3

r

「r」1文字でscala.util.matching.Regexのインスタンスが取れる。正規表現の準備が楽になりそう。

scala> "([0-9]{4})" r
scala.util.matching.Regex = ([0-9]{4})

// 置換してみる
scala> ( "([0-9]{4})" r ) replaceFirstIn("2011/5/5", "xxxx")
String = xxxx/5/5

reduceLeft / reduceRight

reduceも用意されているのだけど、良い用途が思いつかない。

// とりあえず強引に文字を足してみるとか意味のないことをしてみる
scala> "abc" reduceLeft((x, y) => (x.toInt + y.toInt).toChar)

replace / replaceAll / replaceFirst

java.lang.Stringの機能。文字列を置換する。

scala> "JavaJava".replaceAll("Java", "Scala")
java.lang.String = ScalaScala

scala> "JavaJava".replaceFirst("Java", "Scala")
java.lang.String = ScalaJava

repr

StringOpsからラップしているStringに触りたい時などに内部的に使っている。これ、protectedじゃいけないのだろうか。

// StringOpsを利用
scala> val mac = new scala.collection.immutable.StringOps("Mac")
scala.collection.immutable.StringOps = Mac

// reprでStringクラスが取れる
scala> mac.repr
String = Mac

普通はtoStringしそうな気もする。いや、普通はStringOpsを明示的に使うことなんてないか。

reverse

文字列を逆順にする。

scala> "Windows" reverse
String = swodniW

reverseIterator

文字列を逆順に回すIteratorを取得する

scala> ("Windows" reverseIterator) foreach print
swodniW

reverseMap

mapのreverse版。

// 逆さまにして大文字に変換してみる
scala> "Linux" reverseMap(_.toUpper)
String = XUNIL

sameElements

Iterableなものと中身が同じかどうか比較する。

// Listと比較しても、同じものが入ってればtrue
scala> "Mac" sameElements List('M', 'a', 'c') 
Boolean = true

// 順序も同じでないといけない
scala> "Mca" sameElements List('M', 'a', 'c')
Boolean = false

scanLeft / scanRight

scanLeftは左から右に、scanRightは右から左に結果を持ち越しながら処理を実行する。

// こんな風に書くものだけど、Stringでの用途が思いつかない
scala> (1 to 5).scanLeft(1){_ + _}
scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 4, 7, 11, 16)

segmentLength

prefixLengthが内部的に利用しているもの。指定したインデックスから条件に合う文字が連続する数を拾ってきてくれる。

// 3文字目以降で大文字が連続する数
scala> "xxxXXXxxx" segmentLength(_.isUpper, 3)
Int = 3

size

lengthと同じ。文字数をカウントする。

slice / substring

部分文字列を取り出す。java.lang.Stringのsubstringは文字列より大きいレンジを指定すると例外が起きたが、sliceは範囲より大きい値が指定された場合は文字列の終端まで取得するなど配慮してくれている。

// 文字数を超える値を指定しても大丈夫
scala> "Windows" slice(3, 10)
String = dows

// substringでは例外
scala> "Windows" substring(3, 10)
java.lang.StringIndexOutOfBoundsException: String index out of range: 10

// -1やstartとendが違う値を入れるなどした場合は、空文字が返る
scala> "Windows" slice(-1, -5)        
res114: String =

sliding

指定した文字数でスライドしながらiteratorを作る。

// 3を指定すると、1文字ずつスライドしながら3文字区切りのIteratorを返す
scala> "Windows".sliding(3).toList   
List[String] = List(Win, ind, ndo, dow, ows)

// デフォルトのstepは1
scala> "Windows".sliding(3, 1).toList
List[String] = List(Win, ind, ndo, dow, ows)

// stepが2になると、2個ずつスライドする
scala> "Windows".sliding(3, 2).toList
List[String] = List(Win, ndo, ows)

sorted / sortBy / sortWith

条件でソートする

scala> "Wimax" sorted         
res11: String = Waimx

scala> "Wimax" sortBy(c => c)               
String = Waimx

scala> "Wimax" sortWith(_ > _) 
String = xmiaW

span

条件に当てはまる間の値と、それ以降の値とで分割する。

// 大文字である間の文字列と、それ以降の文字列で分割
scala> "WinWin".span(_.isUpper)
(String, String) = (W,inWin)

split

文字列を分割する。java.lang.Stringには正規表現を使って分割するsplit関数がいる。

ScalaはChar、もしくはArray[Char]でセパレータを指定して分割するsplit関数がいる。

// Java版
scala> "2011/5/5 10:22:33" split "[\\/\\:%s]"
Array[java.lang.String] = Array(2011, 5, 5 10, 22, 33)

// Scala版(Char指定)
scala> "2011/5/5" split '/'    
Array[String] = Array(2011, 5, 5)

// Scala版(Array[Char]指定)
scala> "2011/5/5 10:22:33" split Array('/', ':', ' ')
Array[String] = Array(2011, 5, 5, 10, 22, 33)

splitAt

指定したposで文字列を分割する。

scala> "Firefox" splitAt 3
(String, String) = (Fir,efox)

startsWith

文字列の始端が指定された文字列になっているか確認する。

scala> "Firefox" startsWith "Fire"             
Boolean = true

// 第2引数に数値を入れると、その場所からの文字列で評価
scala> "Firefox" startsWith("fox", 4) 
Boolean = true

stripLineEnd

文字列の末尾の改行を削除する

scala> "ONE\n".stripLineEnd

stripMargin

Scalaの文字列はダブルコーテーションを3つ繋げると、複数行にわたって記述できる。

scala> val str = """Firefox  
     | Opera
     | Chrome"""
str: java.lang.String = 
Firefox
Opera
Chrome

しかし、上記のように書くとインデントがイマイチ。それを解決するのが、stripMarginらしい。デフォルトでは「|」をmarginCharに設定して、それが出現した以降の文字列のみ有効にしてくれる。

scala> val str = """Firefox
     |           |Opera    
     |           |Chrome""".stripMargin
str: String = 
Firefox
Opera
Chrome

「|」以外にも任意のmarginCharを指定可能。以下は「%」を指定した場合。

scala> val str = """Firefox
     |           %Opera    
     |           %Chrome""".stripMargin('%')
str: String = 
Firefox
Opera
Chrome

stripPrefix

指定した文字列で開始していたら(内部的にはstartsWithで判定)、その指定文字部分を取り除く。

// Opera - Ope = ra
scala> "Opera" stripPrefix "Ope"
java.lang.String = ra

// 開始文字列が一致しなければ、そのままの文字列を返す
scala> "Opera" stripPrefix "IE" 
java.lang.String = Opera

stripSuffix

stripPrefixの逆版。こちらはendsWithで判定。

cala> "Opera" stripSuffix "ra" 
java.lang.String = Ope

sum

文字をコード的な数字にして合算する。Collection的なものには付いてくる機能。たぶん文字列でこれは使わない。

scala> "abc" sum
  //=> 良く分からない文字が出力される

tail

1つ目の要素を除いて、それ以外の要素を取得する関数。

scala> "chrome" tail
String = hrome

take / takeRight / takeWhile

takeは前方から指定文字数分取得。takeRightは後方から指定文字数分取得。

takeWhileは条件に合致している間の文字列を取得。

// take
scala> "chrome" take 3
String = chr

// takeRight
scala> "chrome" takeRight
String = ome

// takeWhile(oが出現するまで)
scala> "chrome" takeWhile(_ != 'o')
String = chr

toArray / toCharArray

Char配列を取得する。toCharArrayはjava.lang.Stringの同様の機能。

scala> "ie" toArray
Array[Char] = Array(i, e)

scala> "ie" toCharArray
Array[Char] = Array(i, e)

toInt / toByte / toFloat / toDouble / toBoolean

他の型への変換。

scala> "10" toInt
Int = 10

scala> "10" toDouble
res71: Double = 10.0

// 数値でないものを変換すると例外
scala> "foo" toDouble
java.lang.NumberFormatException: For input string: "foo"

// toBooleanは文字列がtrueもしくはfalse(Ignore Case)の場合に変換可能
scala> "True" toBoolean
Boolean = true

// true/false以外をtoBooleanすると例外
scala> "Trururu" toBoolean
java.lang.NumberFormatException: For input string: "Trururu"

toList / toBuffer / toIterator / toSeq / toSet

ScalaのCollection的な機能に変換できる。

scala> "mono" toList
List[Char] = List(m, o, n, o)

scala> "mono" toBuffer
scala.collection.mutable.Buffer[Char] = ArrayBuffer(m, o, n, o)

toUpperCase / toLowerCase

java.lang.Stringの機能。大文字、小文字変換。

scala> "Linux" toUpperCase  
java.lang.String = LINUX

scala> "WINDOWS" toLowerCase
java.lang.String = windows

trim

java.lang.Stringの機能。前方と後方の空白文字を除去する。

scala> "\ntsu ka re ta \n" trim
java.lang.String = tsu ka re ta

withFilter

フィルタをかけた上で、mapとかforeachを実行できる。

// 「o」より小さい物だけ取り出す
scala> "Windows".withFilter(_ < 'o').map(c => c)  
String = Wind

zip / zipAll

2つの文字列の同じ位置をペアにする。zipは長さが一致しない場合は、短い方に合わせる。

zipAllは長さが一致しない場合に、残りを指定した値で埋める。2つ目の引数がthis側、3つ目の引数がthat側を埋める文字。

scala> "1567" zip "2482"     
scala.collection.immutable.IndexedSeq[(Char, Char)] = Vector((1,2), (5,4), (6,8), (7,2))

// 長さが一致しない場合
scala> "1567" zip "248" 
scala.collection.immutable.IndexedSeq[(Char, Char)] = Vector((1,2), (5,4), (6,8))

// zipAll
scala> "1568".zipAll("24", '0', '5')   
res105: scala.collection.immutable.IndexedSeq[(Char, Char)] = Vector((1,2), (5,4), (6,5), (8,5))