概要
NSDataDetector クラスを利用して URL を検出し、その結果を考察する。
今回の動作確認環境
Xcode 8.3.3 + Swift 3.1 + Playground
ソースコード
import UIKit
/**
文字列内のURLを検出する
- parameter str: 調査対象の文字列
- returns: 検出したURL情報(NSTextCheckingResult)の配列
*/
func detectLinks(_ str: String) -> [NSTextCheckingResult] {
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
if let d = detector {
return d.matches(in: str, range: NSMakeRange(0, str.characters.count))
} else {
return []
}
}
/**
URL情報を出力する
- parameter links: URL情報(NSTextCheckingResult)の配列
*/
func printLinks(_ links: [NSTextCheckingResult]) {
links.forEach {
// NSRange
print("range.location: \($0.range.location)")
print("range.length: \($0.range.length)")
// URL?
print("url: \(String(describing: $0.url))")
print("")
}
}
// テストパターン
let tests: [String] = [
"hello, world", // URL無し
"https://niwasawa.github.io/ hello", // 文字列の先頭にURL
"hello https://niwasawa.github.io/", // 文字列の末尾にURL
"hello https://niwasawa.github.io/ http://d.hatena.ne.jp/niwasawa/ goodbye", // 複数のURL
"hello https://niwasawa.github.io/ https://niwasawa.github.io/ goodbye", // 同じURLが複数出現
"hellohttps://niwasawa.github.io/ http://d.hatena.ne.jp/niwasawa/ goodbye", // URLの前に文字列
"https://niwasawa.github.io/あ http://d.hatena.ne.jp/niwasawa/%E3%81%82", // 日本語を含むURL
"http://a", // 不完全なURL
"hoge://a", // hogeなURL
]
tests.forEach {
let links = detectLinks($0)
print("======================================================================")
print("test: [\($0)]\n")
printLinks(links)
}
出力結果
======================================================================
test: [hello, world]
======================================================================
test: [https://niwasawa.github.io/ hello]
range.location: 0
range.length: 27
url: Optional(https://niwasawa.github.io/)
======================================================================
test: [hello https://niwasawa.github.io/]
range.location: 6
range.length: 27
url: Optional(https://niwasawa.github.io/)
======================================================================
test: [hello https://niwasawa.github.io/ http://d.hatena.ne.jp/niwasawa/ goodbye]
range.location: 6
range.length: 27
url: Optional(https://niwasawa.github.io/)
range.location: 34
range.length: 31
url: Optional(http://d.hatena.ne.jp/niwasawa/)
======================================================================
test: [hello https://niwasawa.github.io/ https://niwasawa.github.io/ goodbye]
range.location: 6
range.length: 27
url: Optional(https://niwasawa.github.io/)
range.location: 34
range.length: 27
url: Optional(https://niwasawa.github.io/)
======================================================================
test: [hellohttps://niwasawa.github.io/ http://d.hatena.ne.jp/niwasawa/ goodbye]
range.location: 0
range.length: 32
url: Optional(hellohttps://niwasawa.github.io/)
range.location: 33
range.length: 31
url: Optional(http://d.hatena.ne.jp/niwasawa/)
======================================================================
test: [https://niwasawa.github.io/あ http://d.hatena.ne.jp/niwasawa/%E3%81%82]
range.location: 0
range.length: 28
url: Optional(https://niwasawa.github.io/%E3%81%82)
range.location: 29
range.length: 40
url: Optional(http://d.hatena.ne.jp/niwasawa/%E3%81%82)
======================================================================
test: [http://a]
range.location: 0
range.length: 8
url: Optional(http://a)
======================================================================
test: [hoge://a]
range.location: 0
range.length: 8
url: Optional(hoge://a)
考察
- 不完全なURLも検出される
- URLに日本語が混じっていてもパーセントエンコーディングされた結果が検出される
- 文字列内に同じURLが存在していてもそれぞれ検出される
- 「hellohttps://a」や「hoge://a」のようなURLも検出される
- NSDataDetector で検出した結果について、要件に合うようにフィルタリングするのが良さそう