🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1457閲覧

Swift Kotlinから移植した正規表現がSwiftではindex is out of boundsになる

nomura0911

総合スコア1

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2021/02/13 16:54

前提・実現したいこと

文字列を正規表現で分けて配列に追加したいのですが、エラーが出てしまっています。
元々Kotlinの実装で問題なく使用できていたので、swift側の処理で問題が起きているのだと思うのですが原因がわからないため、問題の原因と、解決方法をご教示いただきたいです。

よろしくお願いします!

下図が実装と問題のエラーになります。
イメージ説明

発生している問題・エラーメッセージ

Fatal error: String index is out of bounds: file Swift/StringCharacterView.swift, line 60

該当のソースコード

Swift

1let string = "Google,Amazon,Facebook,Apple" 2let pattern = "\"([^\"]+?)\",?|([^,]+),?|," 3let regex = try! NSRegularExpression(pattern: pattern, options: []) 4let results = regex.matches(in: string, options: [], range: NSRange(0..<string.count)) 5var texts: [String] = [] 6 7for result in results { 8 for i in 0..<result.numberOfRanges { 9 let start = string.index(string.startIndex, offsetBy: result.range(at: i).location) 10 let end = string.index(start, offsetBy: result.range(at: i).length) 11 let text = String(string[start..<end]) 12 texts.append(text) 13 print(texts) 14 } 15}

処理は以下のサイトを参考にしました。
https://www.2nd-walker.com/2020/04/21/swift-how-to-use-nsregularexpression/

移植元のKotlinでは以下のコードで期待通りに動作しています。

Kotlin

1fun test(): List<String> { 2 val pattern = "\"([^\"]+?)\",?|([^,]+),?|,".toPattern() 3 val string = "Google,Amazon,Facebook,Apple,Asia" 4 val matcher = pattern.matcher(string) 5 val texts = mutableListOf<String>() 6 while (matcher.find()) { 7 texts.add(matcher.group()) 8 } 9 return texts.toList() 10}
実行結果: [Google,, Amazon,, Facebook,, Apple,, Asia]

,,となっているのは想定通りですので気にしないでください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんな感じでしょうか。

  • 文字列全体を表す NSRange の length は UTF16 表現での長さなので、string.count ではなく string.utf16.count を渡す必要があります。
  • 配列 results の各要素 result ですが、例えば "Amazon,Facebook", が正規表現 "([^"]+?)",? にマッチした場合、range および range(at: 0) はマッチした文字列全体である "Amazon,Facebook",、range(at: 1) は正規表現の各 () にマッチした部分 Amazon,Facebook となります。今回は result.range だけ使えばいいのでは。
  • 文字列 string の部分を表す NSRange を Range<String.Index> に変換するには Range の init?(_ range: NSRange, in string: String) を使うと良いでしょう。

Swift

1let string = "Google,\"Amazon,Facebook\",,Apple,????,????,????,????,????" 2let pattern = "\"([^\"]+?)\",?|([^,]+),?|," 3let regex = try! NSRegularExpression(pattern: pattern, options: []) 4let results = regex.matches(in: string, range: NSRange(0..<string.utf16.count)) 5var texts: [String] = [] 6 7for result in results { 8 let text = String(string[Range(result.range, in: string)!]) 9 texts.append(text) 10 print(texts) 11} 12 13// 最終結果 14// ["Google,", "\"Amazon,Facebook\",", ",", "Apple,", "????,", "????,", "????,", "????,", "????"] 15

投稿2021/02/13 21:21

hoshi-takanori

総合スコア7899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nomura0911

2021/02/14 03:33

ご回答いただきありがとうございます! 上記でエラーなく動作することを確認できました! string.utf16.countとする必要があったのですね。調査不足でした。 また配列の各要素に対するより良い書き方も教えてくださりありがとうございます! swiftの文字列操作難しいですね...精進します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問