概要
URLが表現された文字列をSwift URLクラスにする場合、
let url = URL(string: "https://qiita.com")
のような書き方をすると思います。
これでURLの処理をしていくことになります。
しかし、日本語が含まれるURL、例えば、
総務省のWikipedia https://ja.wikipedia.org/wiki/総務省
なんかだと、
let url = URL(string: "https://ja.wikipedia.org/wiki/総務省")
print(url) // nil
このように日本語のURLはnilになります。
なので、これを日本語URLに対応するようにします。
URLComponentsで日本語URL対応する
日本語URL対応のためURLComponentsを使います。
ドキュメントにも書いてありますが、URLComponentsのpath
やquery
などのプロパティは、パラメータをセットするとそれぞれのコンポーネントに合わせたパーセントエンコーディングをしてくれます。
もともとのURL文字列からの各種コンポーネント取り出しはNSRegularExpression
を使っての正規表現でがんばります。
以下はpathやqueryに対応したコードになります。
正規表現でグループ化したコンポーネントはNSTextCheckingResult.range(at:)
でそれぞれ取り出し、URLComponentsのhostやpathに渡してます。
extension URL {
init?(urlString: String?) {
guard let urlString = urlString,
let regex = try? NSRegularExpression(pattern: #"^(.+?)://(.+?):?(\d+)?(/[^\?]*)\??(.*)?$"#, options: .init()),
let ret = regex.matches(in: urlString, options: .init(), range: .init(location: 0, length: urlString.count)).first
else {
return nil
}
var component = URLComponents()
if let range = Range(ret.range(at: 1), in: urlString) {
component.scheme = String(urlString[range])
}
if let range = Range(ret.range(at: 2), in: urlString) {
component.host = String(urlString[range])
}
if let range = Range(ret.range(at: 4), in: urlString) {
component.path = String(urlString[range])
}
if ret.range(at: 5).length > 0,
let range = Range(ret.range(at: 5), in: urlString) {
component.query = String(urlString[range])
}
if let url = component.url {
self = url
} else {
return nil
}
}
}
こうすることで、パーセントエンコーディングされたURLが作成でき、処理が可能になります。
fragmentなどには対応していないので、各自アレンジしてください。
let url = URL(urlString: "https://ja.wikipedia.org/wiki/総務省")
print(url) // https://ja.wikipedia.org/wiki/%E7%B7%8F%E5%8B%99%E7%9C%81