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

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

ただいまの
回答率

91.02%

  • Swift

    6082questions

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

textViewにおいてボタンをタップしたらカーソルの右(左は成功しています)の文字を1字削除するコード

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 236

Tomzy

score 65

やりたいこと

textViewにおいてボタンをタップしたらカーソルの右の文字を1字削除することです。

経緯

これは別の質問98989でxAxisさんに教えて頂いて左の文字を1字削除することを解決しましたので、そのコードを流用して実装を試みました。

実装結果

右側の文字を削除することは成功しましたが、下記の点が目指すやりたいことと違います。

  • 右の文字が1字だけでなく全部消えてしまいます。
  • 最後にカーソルの右に1字残っている場合は削除されません。

実装したコード

   //キャレットが一番右にある場合削除する文字がないので抜ける
    if offset <= 0 {
    return
    }
    //テキストがない場合抜ける
    guard let fullText = InputView.text else {
    return
        print("ここまで来た08")
    }

    let startIndex = fullText.startIndex
    let endIndex = fullText.endIndex

        print("ここまで来た09")

    //UITextView.index(_,offsetBy:)のoffsetByは負の数だと落ちる
    let targetOfLeftIndex = fullText.index(startIndex, offsetBy: offset)
        print("ここまで来た10")
        let targetOfRightIndex = fullText.index(fullText.endIndex, offsetBy: 0)

    let leftText = fullText[startIndex..<targetOfLeftIndex]
    let rightText = fullText[targetOfRightIndex..<endIndex]
    print("ここまで来た11")
    let modifiedText = leftText + rightText

    InputView.text = String(modifiedText)

}

考察

カーソルを境に文字列を左右に分けて
targetOfLeftIndex と
targetOfRightIndex
を定義しました。

targetOfLeftIndexは文字列頭と尾までの文字列とし
targetOfRightIndexはfullText.endIndex, offsetBy: 0 としました。

最後にleftText + rightTextを表示するようにしました。

最初はfullText.endIndex, offsetBy: -1 と定義したのですが、
削除はするもののカーソルの右1字の削除ではありませんでした。

質問

targetOfRightInde
に最初の文字をはずして最後までの文字列を取得するコードを教えてください。

ご参考事項

環境は下記のとおりです。
MacBook Pro (15-inch, 2016)
High Sierra OS10.13
Version 9.1 (9B55)Swift4にバージョンアップしました。
下記のように定義しています。
@IBOutlet weak var InputView: UITextView!
@IBOutlet weak var Sentaku02: UIButton!
画面は下記のとおりです。最初はキーボードはでておらず画面をタップして文字記入後削除ボタンを押して文字を消したいと思っております。
イメージ説明

イメージ説明
以上よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

前書き

これは絵文字のことを考慮していないアプローチです。絵文字を考慮したものは回答の最下部に書いてみました。

実装の流れ

今回実装したい機能の流れとしては

  1. テキストがない場合抜ける
  2. カーソルの位置が一番右にある場合抜ける
  3. ターゲットとする文字の左側のインデックスおよび右側のインデックスの取得を行う。
  4. 文字列の頭からターゲットの左側までの文字列およびターゲットの右側から文字列の最後尾の二つを取得する
  5. 4で取得した文字列の結合

となります。
やることは前回した回答と同じような流れではあるのですが2の場合の抜け方とtargetOfLeftIndexおよびtargetOfRightIndexの取得方法が若干異なります。

型の違い

前回の質問の段階でもっと丁寧にしておけばと思っていたのですが今回その機会がやってきたので少し説明をしておきます。今回出てくる定数のうちstartIndex, endIndex, targetOfLefindex, targetOfRightIndexはString.indexという少々特殊な型です。が一方でoffsetは基本的なIntになります。後述してあるfullText.countも同様にIntです。型が違うのでそのままたし算、ひき算は出来ません。

インデックスについて

インデックスの認識というのは慣れるまで分かりにくいので図を用意してみました。
explanation
この図では文字「お」をターゲットとして定めた場合の各定数、プロパティの名称等をふんわりと図にしたものです(汚いのはご容赦ください)。この時のカーソルの位置は「お」の左側にあります。また左右混乱しやすいのでゆっくり確認してください。

offsetに関してですが、
カーソルが「あ」の左側にある場合

offset == 0


になります。
またカーソルが「く」の左側にある場合

offset == 7


となります。
カーソルが「こ」の右側にある場合は

offset == fullText.count


です。

コーディングの前準備

前回した回答との違いは実のところ2と3だけになります。
前回の質問では2の部分は「カーソルの位置が一番左にある場合抜ける」でした。
そしてカーソルの位置が一番左の時を表すコードは

offset == 0


でした。では「カーソルが一番右にある場合」を表すコードはどうなるでしょうか。使えそうなのはすでに入力されている文字列の量です。

今度考える点は3です。これはつまりtargetOfLeftIndexとtargetOfRightIndexの関係性を考えることになります。これら二つはstartIndexを起点とするとtargetOfLeftIndexはstartIndexからoffset分移動したところにあると言えます。ではtargetOfRightIndexはというとstartIndexからoffset分移動したところにあるtargetOfLeftIndexの一つ隣になります。

以上を考えた上でコーディングを行なっていきます。

サンプルコード

        //(1)
        guard let fullText = textView.text else {
            return
        }

        //(2)
        let count = fullText.count
        let offset = textView.selectedRange.location
        if offset >= count {
            return
        }

        //(3)
        let startIndex = fullText.startIndex
        let endIndex = fullText.endIndex
        let targetOfLeftIndex = fullText.index(startIndex, offsetBy: offset)
        let targetOfRightIndex = fullText.index(startIndex, offsetBy: offset + 1)  //targetOfLeftIndexの一つ隣

        //(4)
        let leftText = fullText[startIndex..<targetOfLeftIndex]
        let rightText = fullText[targetOfRightIndex..<endIndex]

        //(5)
        let modifiedText = leftText + rightText
        textView.text = String(modifiedText)

絵文字が混ざった場合

        /*
         事前情報

         今回絵文字が含まれているのでUTF16に関する知識が多少必要になり、さらにアプローチが上記のものとは部分的に変わっています。
         */

        /*
         アプローチについて

         絵文字を考慮しつつカーソルの右側を削除する場合、考えることは
         1.入力された全ての文字列
         2.startIndexからカーソルまでの文字列
         3.削除する文字数
         4.カーソルの右側に残った文字列の数
         5.UTF16の文字列は「あ」という文字は1文字として認識されるが「😓」という文字は2文字として認識される。さらに色付きの文字だったりすると倍になったりする(詳細はUTF16, unicode等検索して下さい)
         6.5番を踏まえるとカーソルの右が普通の文字であろうと絵文字であろうと対応できるコードを書かなければならない

         1.はfullText
         2.はfullText[startIndex..<cursorIndex]
         3.はカーソルの右側1文字だけなのでamountOfCharacter = 1
         4.は実機等画面に表示されている全ての文字列の数 - leftTextの数 - ammountOfCharacter
         で表します。
         5.これのおかげでUITextView.index(_,offsetBy:)で隣の文字を取得するという方法が使えません。
         6.なので4番で取得した文字列分fullTextから切り取る、という方法を取ります。
         */

        //(1)
        guard let fullText = textView.text else {
            return
        }

        //UITextView.selectedRange.locationで取れる位置はUTF16で換算されているようです(要検証)
        let offset = textView.selectedRange.location
        let count = fullText.utf16.count

        if offset >= count {
            return
        }

        //(2)
        //文字列の最初のインデックス情報
        let startIndex = fullText.utf16.startIndex
        //カーソルのインデックス情報
        let cursorIndex = fullText.utf16.index(startIndex, offsetBy: offset)
        //文字列の最初からカーソルまでの文字列
        let leftText = fullText[startIndex..<cursorIndex]

        //(3),(4)
        //文字数の把握及び計算
        let amountOfFullTextCharacter = fullText.underestimatedCount
        let amountOfLeftTextCharacter = String(leftText).underestimatedCount
        let amountOfDeleteCharacter = 1
        let remain = amountOfFullTextCharacter - amountOfLeftTextCharacter - amountOfDeleteCharacter

        //(5),(6)
        //文字列の末尾からremain分切り取り
        let rightText = fullText.suffix(remain)

        //文字列の結合。カーソルの左側を削除した文字列になる
        let modifiedText = leftText + rightText

        //modifiedTextはsubstringでStringではないのでStringにしてUITextView.textに代入
        textView.text = String(modifiedText)

        //カーソルの位置を元に戻す
        textView.selectedRange.location = offset

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/06 14:46

    あとこれは完全に自分の認識違いでしたが「 UITextView.index(_,offsetBy:)のoffsetByは負の数だと落ちる」というよりは「UITextView.index(_,offsetBy:)で取得しようとした値が負の数だと落ちる」が正しそうです。失礼しました。

    キャンセル

  • 2017/11/06 15:39

    早速ありがとうございました。図はとってもわかり易かったです。
    単にコピーペーストするのではなく、教えて頂いた内容を理解しながらひとつづつコーディングしています。一旦、成功したのですが、キャレットが一番右にきて連続して削除することが難しいのでキャレットの位置をコーディングしている時にエラーになり分からなくなってしまいました。
    少し頭を冷やしてからやりなおします。

    キャンセル

  • 2017/11/06 21:17

    分かり易かったなら自分も嬉しいです。
    ひとつずつコーディングするのは素晴らしいことだと思います。
    やはり文字を削除するとキャレットの位置が先頭に来てしまいますか。削除する機能自体は出来上がりましたがこのままでは使いにくいですね。
    根を詰めてやると自分もよく頭がフリーズしてしまうのでそんな時は不貞寝して翌朝考えたりしますw
    また疑問点がありましたら遠慮なくどうぞ。

    キャンセル

  • 2017/11/07 10:53

    削除後カーソルを削除文字のところにする修正も含めて削除するようにできました。やっている内に偶然良い結果がでてきました。コード上これでよいのでしょうか。コードは下記の通りです。なお、カーソルの左を削除するケースでは、まだカーソル位置を修正することに成功していません。
    //削除→を押した時⇒右の文字を削除
    @IBAction func Sakujo02(_ sender: Any) {
    print("ここまで来た07")

    //キャレットの位置
    // //文字列が"あいうえお"の時、キャレットが""の右側にあるならばoffset == 0

    //

    //テキストがカーソルの右にない場合抜ける
    guard let fullText = InputView.text else {
    return
    print("ここまで来た08")
    }
    let count = fullText.count
    let offset = InputView.selectedRange.location
    if offset >= count {
    return
    }

    let startIndex = fullText.startIndex
    let endIndex = fullText.endIndex

    print("ここまで来た09")

    let targetOfLeftIndex = fullText.index(startIndex, offsetBy: offset)
    print("ここまで来た10")
    let targetOfRightIndex = fullText.index(startIndex, offsetBy: offset + 1)

    let leftText = fullText[startIndex..<targetOfLeftIndex]
    let rightText = fullText[targetOfRightIndex..<endIndex]
    print("ここまで来た11")
    let modifiedText = leftText + rightText

    //削除後の表示
    InputView.text = String(modifiedText)
    print("ここまで来た12")
    //カーソルを削除した文字の後につける
    if InputView.selectedTextRange != nil {

    InputView.selectedRange.location = offset
    print("ここまで来た13")
    }

    }

    キャンセル

  • 2017/11/07 16:49 編集

    カーソルの位置調整は
    InputView.selectedRange.location = offset
    でいいと思います(自分もこれで考えていました)。

    ただif文を書くならばInputView.selectedRange.locationに対してどうなのか?と言う風に考えて書いた方がいいです。
    理由は二つあります。

    (1)InputView.selectedRange.locationは現在あるカーソルの位置です。そしてoffsetは削除前のカーソル位置になります。今挙げた2点の位置が等しくなければ、現在あるカーソルの位置を削除前のカーソル位置に戻す、と考えた方が自然です。そしてコードは自然な書き方をした方が後々見返した時自分自身が楽です。
    (2)あまり深くデバッグしてはいないので確実だとは言えませんがこの関数内の処理ののち(つまり"ここまで来た12"ののち)InputView.selectedTextRangeがnilになることはないと思えます。
    ですから
    InputView.selectedTextRange != nil
    の条件は修正した方がいいと思います。

    ですが
    InputView.selectedRange.location = offset
    を試行錯誤の結果自ら導かれたので位置関係について質問前よりも理解が深まってきていると言えるのではないでしょうか。素晴らしいです。
    カーソルの左側の削除もこの調子でやればきっといけますよ。

    キャンセル

  • 2017/11/08 11:52

    できました。
    InputView.selectedTextRange != nil
    は何かのコードをXcodeが修正してくれたコードです。削除しましたが、機能しました。

    カーソルの左を削除する場合は下記で上手く行きました。

    //削除後の表示
    InputView.text = String(modifiedText)

    //カーソルを削除した文字の後につける

    InputView.selectedRange.location = (offset-1)

    ありがとうございました。

    キャンセル

  • 2017/11/08 11:54

    全角、半角いずれもカーソル移動、削除が機能しています。

    キャンセル

  • 2017/11/08 12:03

    実機でも機能します。とても使い勝手がよく、これならアプリとして出す価値があると感じました。
    特に音声入力は文章の修正が頻繁に必要になります。しかし、年寄りにとっては指が乾燥するので標準の仕様ではカーソルの移動が難しく、特にカーソルの右側にある文字を削除する機能は標準には装備されていないので、この音声入力アシストを使えば、容易に修正ができます。あと、選択、コピーペースト、メール転写などのコーディングをやりたいと思っています。

    キャンセル

  • 2017/11/09 09:25

    左右の文字を削除する関数が出来上がって良かったです。
    音声入力は意外と修正が必要になりますよね。自分も数字の計算をSiriにお願いする時たまに使うのですがそれでもちょくちょく修正に迫られてます。
    あと三つの機能のコーディング上手くいくと良いですね!

    キャンセル

  • 2017/11/13 14:40

    絵文字を削除しようとすると途中で落ちることがわかりました。まだ、課題です。これから勉強します。

    キャンセル

  • 2017/11/13 16:16

    こちらでも試して状況を確認しました。自分の方では落ちることはなかったのですがこのままではどうにもならないですね。アプローチを少々変えないといけないです。しかし絵文字の存在を全く忘れていました。
    平たく言うと「😓」と言う文字1文字で「あ」と言う文字の数倍の文字分必要になるんですよね。

    キャンセル

  • 2017/11/13 20:02

    自分の方でも色々検証してみたのですがなかなか難儀しそうな課題ですね。UITextView.selectedRange.locationで取れる位置情報はどうもUTF16で換算しているようでそこが問題ですね。

    キャンセル

  • 2017/11/13 20:03

    guard let fullText = textView.text else {
    return
    }
    let count = fullText.utf16.count
    let offset = textView.selectedRange.location

    if offset >= count {
    return
    }

    let startIndex = fullText.utf16.startIndex
    let endIndex = fullText.utf16.endIndex

    let targetOfLeftIndex = fullText.utf16.index(startIndex, offsetBy: offset)

    let targetOfRightIndex = fullText.utf16.index(after: targetOfLeftIndex)


    let leftText = fullText[startIndex..<targetOfLeftIndex]
    let rightText = fullText[targetOfRightIndex..<endIndex]

    let modifiedText = leftText + rightText

    textView.text = String(modifiedText)

    キャンセル

  • 2017/11/13 20:07 編集

    これで一応絵文字も普通の文字も消せるようにはなったのですが絵文字を消した場合「?」が残るのでtargetOfRightIndexの調整が必要まだまだです。

    キャンセル

  • 2017/11/13 20:28 編集

    コメントしたばかりであれなんですけど閃いたんでとりあえずなんとかなりそうです。

    キャンセル

  • 2017/11/13 20:25 編集

    guard let fullText = textView.text else {
    return
    }

    let count = fullText.utf16.count
    let offset = textView.selectedRange.location

    if offset >= count {
    return
    }

    let startIndex = fullText.utf16.startIndex

    let targetOfLeftIndex = fullText.utf16.index(startIndex, offsetBy: offset)

    let leftText = fullText[startIndex..<targetOfLeftIndex]
    let amountOfCharacter = 1
    let remain = fullText.underestimatedCount - String(leftText).underestimatedCount - amountOfCharacter

    let rightText = fullText.suffix(remain)

    let modifiedText = leftText + rightText

    textView.text = String(modifiedText)

    textView.selectedRange.location = offset

    キャンセル

  • 2017/11/13 20:29

    Tomzyさんの課題を勝手に手を出すのは図々しいかとは思いましたがswift4になってまだ日が浅く情報量もまだ少ないので僭越ながらコードを書きました。よろしければテストをお願いします。

    キャンセル

  • 2017/11/14 15:04

    全選択をやっていて⇒解決しました。 このコメントを見ないでいました。これからでかけるので、夜拝見致します。折角やって頂いたのに、レスポンスが遅くなりごめんなさい。

    キャンセル

  • 2017/11/14 17:29

    お気になさらずまた出来る時でどうぞ。

    キャンセル

  • 2017/11/14 22:25

    上手く消えました。
    下記のコードに変換をして試しました。全角日本語、半角英数字、顔文字すべてカーソルの右の文字を消すことができました。

    ありがとうございました。これを勉強してカーソルの左の文字を消すこともトライします。
    取り急ぎご報告申し上げます。

    // //削除→を押した時⇒右の文字を削除
    @IBAction func Sakujo02(_ sender: Any) {
    print("ここまで来た07")
    guard let fullText = InputView.text else {
    return
    }

    let count = fullText.utf16.count
    let offset = InputView.selectedRange.location

    if offset >= count {
    return
    }

    let startIndex = fullText.utf16.startIndex

    let targetOfLeftIndex = fullText.utf16.index(startIndex, offsetBy: offset)

    let leftText = fullText[startIndex..<targetOfLeftIndex]
    let amountOfCharacter = 1
    let remain = fullText.underestimatedCount - String(leftText).underestimatedCount - amountOfCharacter

    let rightText = fullText.suffix(remain)

    let modifiedText = leftText + rightText

    InputView.text = String(modifiedText)

    InputView.selectedRange.location = offset
    }

    キャンセル

  • 2017/11/14 22:55

    報告とテストありがとうございます。そして急かすような真似をしてしまいすいませんでした。上手く消えて本当によかったです。

    絵文字に関して色々と調べたのですが国内では情報が元々少ない&海外の人たちは絵文字はそもそも入力させないというアプローチが多かったです。重ねてswift4ではStringの扱いがswift3とは方向性が変わっておりました。なので今回改めて自分がとったアプローチは回答とは少々ズレたものになってしまいました。このままだと少々まずいと思いますので近いうちに回答の編集を行うつもりです。

    もし右方向の削除をトライされた後、また今回の追記内容に疑問点がありましたら遠慮なくコメントをしてください。

    キャンセル

  • 2017/11/15 15:12

    ありがとうございます。
    カーソルの右側を削除するのは上手く行き、現在カーソルの左を削除するコードを試しています。でていたエラーも解消して、削除はできるのですが、カーソルの右が全部消えるなど不具合がでています。ひきつづき、チェックします。

    現在のコードは下記のとおりです。
    コード
     ↓ ↓ ↓
    @IBAction func Sakujo01(_ sender: Any) {
    print("ここまで来た08b")

    //guard は条件を満たしていない時に、迅速にスコープを抜けるための処理(breakやreturn、例外のthrowなど)を行う。
    //テキストがない場合抜ける

    guard let fullText = InputView.text else {
    return
    }
    //全体の文字数 ⇒黄色マーク"Initialization of immutable value 'count' was never used; consider replacing with assignment to '_' or removing it"⇒let count = が _ =にFixされた

    _ = fullText.utf16.count
    //カーソルの位置を定義
    let offset = InputView.selectedRange.location

    //文字列が"あいうえお"の時、キャレットが"あ"の左側にあるならばoffset == 0
    //キャレットが一番左にある場合削除する文字がないので抜ける
    if offset <= 0 {
    return
    }
    //カーソルの左の文字列
    let startIndex = fullText.utf16.startIndex
    let endIndex = fullText.utf16.endIndex
    //UITextView.index(_,offsetBy:)のoffsetByは負の数だと落ちる

    //1文字のスペース
    let amountOfCharacter = 1
    //カーソルの左より1文字削除後の左の文字列
    let targetOfLeftIndex = fullText.utf16.index(startIndex, offsetBy: offset - amountOfCharacter)
    //カーソルの右側の文字列
    let targetOfRightIndex = fullText.index(startIndex, offsetBy: offset)


    //
    //左の削除後の文字列定義

    //Initialization of immutable value 'remain' was never used; consider replacing with assignment to '_' or removing it⇒Fix Replace 'let remain' with '_'
    let rightText = fullText[targetOfRightIndex..<endIndex]

    _ = fullText.underestimatedCount - String(rightText).underestimatedCount - amountOfCharacter
    let leftText = fullText[startIndex..<targetOfLeftIndex]


    let modifiedText = leftText + rightText

    InputView.text = String(modifiedText)

    InputView.selectedRange.location = offset
    }

    キャンセル

  • 2017/11/15 17:57

    回答に詳細を追記をしました。
    カーソルの右の文字を削除する場合と左の文字を削除する場合、アプローチは反転させる感じになります。

    カーソルの左側を削除する場合、考えることは
    1.入力された全ての文字列
    2.endIndexからoffsetまでの文字列
    3.削除する文字数
    4.カーソルの左側に残った文字列の数
       5.6. 先頭から4.で取得した残りの文字列分切り取り(prefix関数という便利なものがあります)

    コードを読む限りでは左右のアプローチが混ざってしまっていますね。

    キャンセル

  • 2017/11/15 18:36

    自分自身も左右が混乱してきました。完了したのはカーソルの右側を削除する関数で今の課題はカーソルの左側でしたよね?

    キャンセル

  • 2017/11/15 18:39

    カーソルの左側を削除する場合もう一つ(というかこっちの方がはるかに楽な)アプローチがあります。それはUITextView.deleteBackward()を利用する方法です。こっちの方が楽に削除出来るかと。

    キャンセル

  • 2017/11/16 15:12

    できました。下記のコード内にアプローチについても整理しました。
    ただ、絵文字を削除する場合2とか3回ボタンを押す必要があります。右の文字を削除する場合は一発でした。

    コード
     ↓ ↓ ↓
    //←削除を押した時⇒左の文字を削除
    /*
    アプローチについてカーソルの左文字削除について整理

    絵文字を考慮しつつカーソルの左側を削除する場合、考えることは
    1.入力された全ての文字列
    2.startIndexからカーソルまでの文字列
    3.削除する文字数
    4.カーソルの左側に残った文字列の数
    5.UTF16の文字列は「あ」という文字は1文字として認識されるが「😓」という文字は2文字として認識される。さらに色付きの文字だったりすると倍になったりする(詳細はUTF16, unicode等検索して下さい)
    6.5番を踏まえるとカーソルの左が普通の文字であろうと絵文字であろうと対応できるコードを書かなければならない
    7. カーソルの左側を削除する場合もう一つ(というかこっちの方がはるかに楽な)アプローチがあります。それはUITextView.deleteBackward()を利用する方法です。こっちの方が楽に削除出来るかと。

    1.はfullText
    2.はfullText[startIndex..<cursorIndex]
    3.はカーソルの左側1文字だけなのでamountOfCharacter = 1
    4.は実機等画面に表示されている全ての文字列の数 - rightTextの数 - ammountOfCharacter
    で表します。
    5.これのおかげでUITextView.index(_,offsetBy:)で隣の文字を取得するという方法が使えません。
    6.なので4番で取得した文字列分fullTextから切り取る、という方法を取ります。
    7.カーソルの左の1文字を削除する ボタンActionに」より⇒を作動させる InputView.deleteBackward()
    */


    @IBAction func Sakujo01(_ sender: Any) {
    print("ここまで来た08b")

    //guard は条件を満たしていない時に、迅速にスコープを抜けるための処理(breakやreturn、例外のthrowなど)を行う。
    //テキストがない場合抜ける

    guard let fullText = InputView.text else {
    return

    }
    print("ここまで来た08c")

    //カーソルの位置を定義
    let offset = InputView.selectedRange.location

    //文字列が"あいうえお"の時、キャレットが"あ"の左側にあるならばoffset == 0
    //キャレットが一番左にある場合削除する文字がないので抜ける
    if offset <= 0 {
    return
    }
    print("ここまで来た08d")
    //カーソルの左の文字列
    let startIndex = fullText.utf16.startIndex
    let endIndex = fullText.utf16.endIndex

    //1文字のスペース
    let amountOfCharacter = 1
    //カーソルの左の1文字を削除する
    InputView.deleteBackward()
    print("ここまで来た08e")

    //カーソルの左より1文字削除後の左の文字列
    let targetOfLeftIndex = fullText.utf16.index(startIndex, offsetBy: offset - amountOfCharacter)
    //カーソルの右側の文字列
    let targetOfRightIndex = fullText.utf16.index(startIndex, offsetBy: offset)

    //左の削除後の文字列定義

    let leftText = fullText[startIndex..<targetOfLeftIndex]

    let rightText = fullText[targetOfRightIndex..<endIndex]

    let modifiedText = leftText + rightText
    //左の削除後の文字列の表示
    InputView.text = String(modifiedText)

    //カーソルの位置表示
    InputView.selectedRange.location = offset-amountOfCharacter
    }

    キャンセル

  • 2017/12/22 15:23

    xAxisさんへ
    こんにちは。お世話になったアプリがリリースされました。ご報告します。
    「音声入力アシスト」 https://itunes.apple.com/jp/app/id1324919578?mt=8

    キャンセル

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

  • ただいまの回答率 91.02%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    swift3 ボタンのsetTitleについて

    ボタンのタイトルをユーザーが変更した時 文字の長さを全て表示したい場合 ボタンのwidthを文字数に合わせて大きくしたいのですが 可能でしょうか? 色々調べたのですが載

  • 解決済

    UserDefaultsとapp delegate

    ViewController1と2でボタンを押した回数分、ViewController3のラベルの数字が増えていくというものがあります。 ボタンを押した回数は保存したいです。

  • 解決済

    Swiftでアプリから画像を取得したい

    shareExtensionを使用して、他のアプリ(例えばDropbox, EverNoteなど)から 共有ボタン->自作アプリを選択->Post でその画像をUserDefau

  • 解決済

    画面移行で一部の画面を変更する方法

    ここで、エラーが起きてしまいました。 変な題名にしてすみません。 私が思っているのは、Yahoo知恵袋で例えると,マイページの画面で、質問ボタンを押した時、自分が投稿し

  • 受付中

    ボタンをタップしたらDatepickerで指定した日時を取得したい

    前提・実現したいこと ボタンをタップしたらDatepickerで指定した日時を取得したい 試したこと Googleで検索をしているのですが、良い解決方法がありません。ご教

  • 解決済

    UISearchBarのキャンセルボタン

    質問 SearchBarのCancelボタンに関して、デフォルトでは「Cancel」ですがそれを日本語で「キャンセル」と変更したいです。 リファレンスでUISearchba

  • 解決済

    CGDataProviderReleaseDataCallbackが呼ばれない

    前提・実現したいこと CGDataProviderReleaseDataCallbackが呼ばれるようにしたい。 referanceの読み方がわかればできるのかもしれませんが、理解

  • 解決済

    swift3 containerをviewController上のボタンから回転させる方法

    このリンクの質問の内容を発展させ、図の様に、メインのviewController上に、ボタンとcontainerを配置し、ボタンが押される度に、containerをflipすると同

同じタグがついた質問を見る

  • Swift

    6082questions

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

  • トップ
  • Swiftに関する質問
  • textViewにおいてボタンをタップしたらカーソルの右(左は成功しています)の文字を1字削除するコード