使って創ってApp

ソフトウェアを使ったり作ったりするブログです

NSScannerクラスをSwift2.1で少し使ってみました2

NSScannerクラスをSwift2.1で少し使ってみました - 使って創ってAppの続きです。

NSScannerクラスをもう少し使ってみましょう。

下記のサイトを参考にしました。

nshipster.com

実行環境

空白スペースと改行はスキャンが続行される

スキャンに指定した文字列と違う文字列をスキャンしても、その文字列をスキップしてスキャンを続行することができます。デフォルトでは、空白スペースと改行がスキップされます。検索対象を空白スペースや改行にすると、それらを検索してくれます。

let source = "   \n   \n\n     This is a pen."
let scanner = NSScanner(string: source)
var result: NSString?

scanner.scanString("This", intoString: &result)
print(result!)
// This

検索対象から特定の文字を除外する

カンマ・空白スペース・改行をスキップしてスキャンするようにしてみます。

let skipset = NSMutableCharacterSet.whitespaceAndNewlineCharacterSet()
skipset.formUnionWithCharacterSet(NSCharacterSet(charactersInString: ","))

let theScanner = NSScanner(string: ",,,\n,, , This is a pen.")
theScanner.charactersToBeSkipped = skipset

var result: NSString?
theScanner.scanString("This", intoString: &result)
print(result!)
// This

カンマ空白スペース区切りの文字列を、カンマ区切りで分割する

コードはこんな感じ。

let whitespaceAndPunctuationSet = NSMutableCharacterSet.whitespaceCharacterSet()
whitespaceAndPunctuationSet.formUnionWithCharacterSet(NSCharacterSet(charactersInString: ","))

let theScanner = NSScanner(string: "Takeda, Oda, Tyousokabe, Uesugi")
theScanner.charactersToBeSkipped = whitespaceAndPunctuationSet

var name: NSString?
while theScanner.scanUpToString(",", intoString: &name) {
  print(name!)
}
// Takeda
// Oda
// Tyousokabe
// Uesugi

カンマ・空白スペース・改行をスキップ対象にしています。scanUpToStringメソッドでカンマを指定してるので、カンマが見つかった場合のスキャン開始位置がカンマになりそうですが、カンマはスキップ対象なのでスキャン開始位置になりません。今回の場合、一つ目のカンマを見つけた後のスキャン開始位置は Oda の O です。

もう少し難しい文字列をスキャンする

名前と年齢が name:~~ age:~~で書かれ、カンマで区切られる文字列をスキャンします。名前と年齢を抽出します。

let busyous = "name:武田 age:25, name:上杉 age:24, name:織田 age:56"

let whiteSpaceAndCommaCharset = NSMutableCharacterSet.whitespaceCharacterSet()
whiteSpaceAndCommaCharset.formUnionWithCharacterSet(NSCharacterSet(charactersInString: ","))

let scanner = NSScanner(string: busyous)
scanner.charactersToBeSkipped = whiteSpaceAndCommaCharset

var busyoName: NSString?, busyoAge: Int32 = 0
while !scanner.atEnd {
  scanner.scanString("name:", intoString: nil)
  scanner.scanUpToString(" ", intoString: &busyoName)
  scanner.scanString("age:", intoString: nil)
  scanner.scanInt(&busyoAge)
  print("拙者、\(busyoName!)と申す。齢\(busyoAge)なり。")
}
// 拙者、武田と申す。齢25なり。
// 拙者、上杉と申す。齢24なり。
// 拙者、織田と申す。齢56なり。

まとめ

  • NSScannerクラスは、文字列を初めから終わりまで順番にスキャンする
  • スキャン開始位置や、検索対象から特定の文字列を含めないようにできる

スキャン開始位置を頭で追うことが、このクラスを使うのに重要なことだなと感じました。