LoginSignup
6
9

More than 5 years have passed since last update.

SwiftのNSDataDetectorクラスで文字列内にあるURLを検出する

Posted at

概要

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 で検出した結果について、要件に合うようにフィルタリングするのが良さそう

参考資料

6
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
9