回答編集履歴

2

加筆・修正

2017/11/15 08:43

投稿

xAxis
xAxis

スコア1349

test CHANGED
@@ -1,3 +1,11 @@
1
+ ###前書き
2
+
3
+
4
+
5
+ これは絵文字のことを**考慮していない**アプローチです。絵文字を考慮したものは回答の最下部に書いてみました。
6
+
7
+
8
+
1
9
  ###実装の流れ
2
10
 
3
11
 
@@ -163,3 +171,149 @@
163
171
  textView.text = String(modifiedText)
164
172
 
165
173
  ```
174
+
175
+
176
+
177
+ ###絵文字が混ざった場合
178
+
179
+
180
+
181
+ ```swift
182
+
183
+
184
+
185
+ /*
186
+
187
+ 事前情報
188
+
189
+
190
+
191
+ 今回絵文字が含まれているのでUTF16に関する知識が多少必要になり、さらにアプローチが上記のものとは部分的に変わっています。
192
+
193
+ */
194
+
195
+
196
+
197
+ /*
198
+
199
+ アプローチについて
200
+
201
+
202
+
203
+ 絵文字を考慮しつつカーソルの右側を削除する場合、考えることは
204
+
205
+ 1.入力された全ての文字列
206
+
207
+ 2.startIndexからカーソルまでの文字列
208
+
209
+ 3.削除する文字数
210
+
211
+ 4.カーソルの右側に残った文字列の数
212
+
213
+ 5.UTF16の文字列は「あ」という文字は1文字として認識されるが「????」という文字は2文字として認識される。さらに色付きの文字だったりすると倍になったりする(詳細はUTF16, unicode等検索して下さい)
214
+
215
+ 6.5番を踏まえるとカーソルの右が普通の文字であろうと絵文字であろうと対応できるコードを書かなければならない
216
+
217
+
218
+
219
+ 1.はfullText
220
+
221
+ 2.はfullText[startIndex..<cursorIndex]
222
+
223
+ 3.はカーソルの右側1文字だけなのでamountOfCharacter = 1
224
+
225
+ 4.は実機等画面に表示されている全ての文字列の数 - leftTextの数 - ammountOfCharacter
226
+
227
+ で表します。
228
+
229
+ 5.これのおかげでUITextView.index(_,offsetBy:)で隣の文字を取得するという方法が使えません。
230
+
231
+ 6.なので4番で取得した文字列分fullTextから切り取る、という方法を取ります。
232
+
233
+ */
234
+
235
+
236
+
237
+ //(1)
238
+
239
+ guard let fullText = textView.text else {
240
+
241
+ return
242
+
243
+ }
244
+
245
+
246
+
247
+ //UITextView.selectedRange.locationで取れる位置はUTF16で換算されているようです(要検証)
248
+
249
+ let offset = textView.selectedRange.location
250
+
251
+ let count = fullText.utf16.count
252
+
253
+
254
+
255
+ if offset >= count {
256
+
257
+ return
258
+
259
+ }
260
+
261
+
262
+
263
+ //(2)
264
+
265
+ //文字列の最初のインデックス情報
266
+
267
+ let startIndex = fullText.utf16.startIndex
268
+
269
+ //カーソルのインデックス情報
270
+
271
+ let cursorIndex = fullText.utf16.index(startIndex, offsetBy: offset)
272
+
273
+ //文字列の最初からカーソルまでの文字列
274
+
275
+ let leftText = fullText[startIndex..<cursorIndex]
276
+
277
+
278
+
279
+ //(3),(4)
280
+
281
+ //文字数の把握及び計算
282
+
283
+ let amountOfFullTextCharacter = fullText.underestimatedCount
284
+
285
+ let amountOfLeftTextCharacter = String(leftText).underestimatedCount
286
+
287
+ let amountOfDeleteCharacter = 1
288
+
289
+ let remain = amountOfFullTextCharacter - amountOfLeftTextCharacter - amountOfDeleteCharacter
290
+
291
+
292
+
293
+ //(5),(6)
294
+
295
+ //文字列の末尾からremain分切り取り
296
+
297
+ let rightText = fullText.suffix(remain)
298
+
299
+
300
+
301
+ //文字列の結合。カーソルの左側を削除した文字列になる
302
+
303
+ let modifiedText = leftText + rightText
304
+
305
+
306
+
307
+ //modifiedTextはsubstringでStringではないのでStringにしてUITextView.textに代入
308
+
309
+ textView.text = String(modifiedText)
310
+
311
+
312
+
313
+ //カーソルの位置を元に戻す
314
+
315
+ textView.selectedRange.location = offset
316
+
317
+
318
+
319
+ ```

1

修正

2017/11/15 08:43

投稿

xAxis
xAxis

スコア1349

test CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
 
8
8
 
9
- 0. カーソルの位置一番右にある場合抜ける
9
+ 0. テキストない場合抜ける
10
10
 
11
- 0. テキストない場合抜ける
11
+ 0. カーソルの位置一番右にある場合抜ける
12
12
 
13
13
  0. ターゲットとする文字の左側のインデックスおよび右側のインデックスの取得を行う。
14
14
 
@@ -20,7 +20,7 @@
20
20
 
21
21
  となります。
22
22
 
23
- やることは前回した回答と同じような流れではあるのですが1の場合の抜け方とtargetOfLeftIndexおよびtargetOfRightIndexの取得方法が若干異なります。
23
+ やることは前回した回答と同じような流れではあるのですが2の場合の抜け方とtargetOfLeftIndexおよびtargetOfRightIndexの取得方法が若干異なります。
24
24
 
25
25
 
26
26
 
@@ -80,9 +80,9 @@
80
80
 
81
81
 
82
82
 
83
- 前回した回答との違いは実のところ1と3だけになります。
83
+ 前回した回答との違いは実のところ2と3だけになります。
84
84
 
85
- 前回の質問では1の部分は「カーソルの位置が一番左にある場合抜ける」でした。
85
+ 前回の質問では2の部分は「カーソルの位置が一番左にある場合抜ける」でした。
86
86
 
87
87
  そしてカーソルの位置が一番左の時を表すコードは
88
88
 
@@ -112,13 +112,17 @@
112
112
 
113
113
 
114
114
 
115
- //(2)
115
+ //(1)
116
116
 
117
117
  guard let fullText = textView.text else {
118
118
 
119
119
  return
120
120
 
121
+ }
122
+
123
+
124
+
121
- }//(1)
125
+ //(2)
122
126
 
123
127
  let count = fullText.count
124
128