質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.49%
iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

Q&A

解決済

3回答

2182閲覧

Swiftで@(アットマーク)を%40(URLエンコード)に変換したい

u-ta

総合スコア60

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

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

0グッド

0クリップ

投稿2017/12/05 11:22

###前提・実現したいこと
Swift4、iOSアプリで、@(アットマーク)をURLエンコードしたい。

入力されたLINEの友達URL

例: https://line.me/R/ti/p/@abcdefg

をopenURLする際に、@を%40にしないとLINEが正しく読み取れないため
@(アットマーク)をURLエンコードしたいのですが変換がうまくいきません。

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

@をreplacingOccurrencesで%40へ置き換えると%40ではない値になる。
@は消えるが、withをうまく指定できません。

swift

1var base:String = "https://line.me/R/ti/p/@abcdefg" 2var replace:String = base.replacingOccurrences(of:"@", with:"%40") 3NSLog("replace 1 :(replace)") 4replace = base.replacingOccurrences(of:"@", with:"%x") 5NSLog("replace 2 :(replace)") 6replace = base.replacingOccurrences(of:"@", with:"x") 7NSLog("replace 3 :(replace)")

console

1replace 1 :https://line.me/R/ti/p/ 0x0p+0bcdefg 2replace 2 :https://line.me/R/ti/p/0abcdefg 3replace 3 :https://line.me/R/ti/p/xabcdefg

replace1の空白はxcodeのコンソールのままです。

###補足情報(言語/FW/ツール等のバージョンなど)
swift4

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

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

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

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

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

guest

回答3

0

ベストアンサー

ピンポイントでの置換なら、

swift

1base.replacingOccurrences(of:"@", with:"%%40") //`%`はメタ文字 2//=> https://line.me/R/ti/p/%40abcdefg

汎用的にURLエンコードしたいなら、

swift

1"@abcdefg".addingPercentEncoding(withAllowedCharacters: .alphanumerics) 2//=> %40abcdefg

訂正

メタ文字はメタ文字でも、NSLogのメタ文字でした。

swift

1var replace = base.replacingOccurrences(of: "@", with: "%40") 2print("replace 1 :(replace)") 3//=> replace 1 :https://line.me/R/ti/p/%40abcdefg

これで変換自体は正しくできています。

おかしかったのはNSLogの使い方で、

swift

1NSLog("replace 1 :(replace)") //これは 2NSLog("replace 1 :https://line.me/R/ti/p/%40abcdefg") //これと同じ意味

なので、%40aという書式を指定していることになります。さらに引数の指定無し。
%aというのは浮動小数点の16進表記(?)だそうで、
空白 + 0x0p+0 + bcde = 0x0p+0bcdefg
という表示になってしまっていたのです。

正しくは、

swift

1NSLog("replace 1 :%@", replace) 2//=> replace 1 :https://line.me/R/ti/p/%40abcdefg

となります。

投稿2017/12/06 00:25

編集2017/12/06 04:45
fuzzball

総合スコア16731

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

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

u-ta

2017/12/06 03:08

ありがとうございます。 ピンポイントでの置換にしました。 urlQueryAllowedですマルチバイト対応をしていましたが@が対象とならないのですが alphanumericsだとhttps://などの置き換えられてしまったので、今回replacingOccurrencesを検討していました。 メタ文字だったんですね。 https://stackoverflow.com/questions/3439853/replace-occurrences-of-space-in-url をみて、通常の文字だと勘違いしてしまっていました。 ありがとうございました。
fuzzball

2017/12/06 04:50 編集

ん?と思って調べたら勘違いでした。回答に「訂正」を追記しました。 ついでに、 >>alphanumericsだとhttps://などの置き換えられてしまったので 普通は丸ごとエンコードしないと思います。
u-ta

2017/12/06 06:37

ありがとうございます、 NSLOGの見えかたの問題ということですね。 当初の下記のコードにしてテストしています。 var replace = base.replacingOccurrences(of: "@", with: "%40") >>alphanumericsだとhttps:// 文が足りてませんでした、パス区切りの/や?が変換されるので サーバー側などふくめて確認する必要がありるのかと考えていました。 URLEncodeの種類?RFCなのかわかりませんがもろもろ影響調査が必要なのかと考えており、alphanumericsは使っていませんでした。 AbsoluteURL文字列からURLを生成する際の文字チェック、変換処理(encodeするならどの文字を対象とするか?)などの王道的なものがわかっていません。
guest

0

swift

1let allowed = CharacterSet 2 .urlFragmentAllowed 3 .subtracting(CharacterSet(charactersIn: "@")) 4 5let replaced = base.addingPercentEncoding(withAllowedCharacters: allowed)

こうでしょうか?

投稿2017/12/05 12:24

MasakiHori

総合スコア3384

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

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

u-ta

2017/12/05 12:42

ありがとうございます。 いま移動中なので後ほど試してみます。 replacingOccurrencesでできない理由というか そもそも使い方が違うのでしょうか?
MasakiHori

2017/12/05 13:05

たんに専用の関数があるのに使ってないことに違和感があっただけです。 ちなみに手元ではreplacingOccurrencesを使っても問題がありませんでした。
u-ta

2017/12/06 03:11

メタ文字だと気づきませんでした。 今回の問題はいただいた回答で解決しましたが マルチバイトや@などの対応方法をもう少し調べて見ます。
guest

0

withAllowedCharactersを調べて最適な方法を考えます。

swift

1let base:String = "https://line.me/R/ti/p/@abcdefg/?q1=123&q2=あ" 2var replace:String = base.replacingOccurrences(of:"@", with:"%%40") 3NSLog("replace 1 :(replace)") 4 replace = base.addingPercentEncoding(withAllowedCharacters: .alphanumerics)! 5NSLog("replace 2 :(replace)") 6 replace = base.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! 7NSLog("replace 3 :(replace)") 8 let allowed = CharacterSet.urlFragmentAllowed.subtracting(CharacterSet(charactersIn: "@")) 9 replace = base.addingPercentEncoding(withAllowedCharacters: allowed)! 10NSLog("replace 4 :(replace)")

console

1replace 1 :https://line.me/R/ti/p/%40abcdefg/?q1=123&q2=あ 2replace 2 :https0X0P+00.0000000.000000line0.000000E+00me-4277374514952982788899796294912006593111872596699109871130058268368934249870917275884438706951811490737744992940320538145728883419978032083095270091847783243124681598621026781775093230743988129684695659598216213104477000370263221601824008509252482105344.000000R0.000000ti0.000000p0.000000 0x0p+0bcdefg0.0000000.000000q1 012323D0.000000E+003882 3replace 3 :https://line.me/R/ti/p/@abcdefg/?q1=123&q2=0.000000E+003882 4replace 4 :https://line.me/R/ti/p/ 0x0p+0bcdefg/?q1=123&q2=0.000000E+003882

投稿2017/12/06 03:06

u-ta

総合スコア60

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問