Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

概要

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

参考資料

niwasawa
迷子になりがちな地図・位置情報系プログラマ。
http://niwasawa.hatenablog.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away