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

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

ただいまの
回答率

89.53%

コルーチン内でstring配列から一文字ずつ取り出し、順番に処理したい

解決済

回答 1

投稿 編集

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

torisva

score 17

文字列から一文字、一文字に同時ではなく順番に処理をしたい

☆前提
ソースコードのコルーチン内、while文の部分が処理になります。
SetTextには仮として"ありがとう"と打ち込んであります(状況により変わります)
unityのUI、Buttonを使用しています(OnClick()はそのためのものです)
このスクリプトはButtonにアタッチしています

☆このスクリプトで望む動作
Debug.Log("あ")
Debug.Log("と")
によりコンソールに、「あ」と「と」が表示され、Debug.Log("ぎ")はスルーされるようにしたい
なおかつ「あ」と「と」が表示される間にはfloat Speedのタイムラグが欲しい

☆このスクリプトの制限
・SetTextの文字列は全部で何文字になるかは不定、変動する
・while内のif文も50音すべてに対応させ、その他、数字なども処理に追加する予定
・「あ」「と」「ぎ」、文字列「ありがとう」の場合、「ぎ」は存在しないため処理しない
・「り、が、う」など処理に存在しない文字の場合、処理をしない、ラグも発生しない(「あ」の処理後speedの間をおいて「と」の処理)

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

NullReferenceException: Object reference not set to an instance of an object
(wrapper stelemref) object:stelemref (object,intptr,object)

該当のソースコード

    [SerializeField]
    Text SetText; //処理したい文字列
    [SerializeField]
    float Speed; //次の処理までのラグ用

    string STR;
    string[] arr;
    int i;
    int n;

    public void OnClick() //ボタンをクリックしたときに処理
    {
        n = 0; //リセット処理
        i = 0; //リセット処理
        STR = SetText.text; //STRにSetTextの文字列を代入

        //arr[]string配列にSTRstringから一文字ずつ格納したい
        //格納後コルーチン内で一文字ずつ処理したい


        foreach (char c in STR) //テキストに書かれた文章を一文字ずつ分割して配列にする
        {
            //arr[i] = STR[i].ToString; //???
            arr[i] = STR.Substring(i); //一文字ずつ格納?
            i ++;
        }
        //Debug.Log(arr);
        StartCoroutine(Cor());//コルーチンスタート
    }

    private IEnumerator Cor() //コルーチン
    {
        int messageCount = 0; //リセット処理
        while (STR.Length > messageCount) //テキストに書かれた文字数を超えるまでループ
        {
            if(arr[n] == "あ")
            {
                Debug.Log("あ");
            }
            if (arr[n] == "と")
            {
                Debug.Log("と");
            }
            if (arr[n] == "ぎ")
            {
                Debug.Log("ぎ");
            }
            n++;
            messageCount++; //ループ処理用
            yield return new WaitForSeconds(Speed); //ループ間のラグ
        }

    }

 試したこと

//途中でコメントアウトしてますが arr[i] = STR[i]          //としてSTRから一文字ずつ取り出せるかな?と思ったのですが、                  //charをstringに変換できませんと表示され arr[i] = STR[i].ToString//としてstringにしようとしましたが、非デリゲート型stringに変換できないと arr[i] = STR(i)         //これも駄目で、string型から指定の文字数の文字を取り出す方法がわかりませんでした arr[i] = STR.SubString(i)//これもできているのかわかっていません                          //Debug.Log(arr)で確認しようとしましたが、コンソールには上記のエラーしか出ません

読み飛ばしていただいても構わない部分 それとありがとうございます

質問を閲覧いただきありがとうございます。

私は初めて配列を使ってスクリプトを組んだのですが、よくわからないところが多くて、
どうにもならず、質問させていただきました。
勝手ながらご教授お願いいたします。

配列を使わない方法などがあればそちらでも構いません。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

文字列(文字が複数あるもの)がstring,文字(1文字だけ)がcharです。
つまり、str[i] はcharを返します。
ですが、strそのものが配列なので、無理に分割する必要はありません

もしstringに入れ直したいならこう書くといいと思います

arr[i] = STR[i].ToString();

コルーチン部分、あとぎ以外の文字でもウエイトが入っているので、
それ以外の文字では入らないようにしましょう

書き換えるならこんな感じですかね 

private IEnumerator Cor(string str, string debug, floot speed ){
  foreach (var c in str){
    if (debug.Any(n => n == c)){
       Debug.Log(c);
       yield return new WaitForSeconds(speed);
    }
  }
}

StartCoroutine(Cor(SetText.text, "あとぎ", 1.0f));

追記

1.Linqが必要です
2.intはミスです、cはcharです
3.n => n == c はラムダ式というもので、bool anonymous(char n){return n == c;} のような意味です
4.ラムダ式を知らないゆえの勘違いだと思うので、それは調べてください
5.anyは、debugの中にある文字のどれか一つとcが一致するかを返す関数です
例はcが"あとぎ"のどれかの文字ならtrueになります
このソースはただの参考ですから、あなたの都合に合わせて書き換えてください

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/22 11:58

    こちらの環境ではそのスクリプトを試すことができないので
    どういう挙動のスクリプトか予想をしつつ、いろいろ聞きたいのですが
    ```
    ①debug.Any
    string型にAnyの定義がない。とのことなので調べましたがusing System.Linqを記述してますか?
    Linqについての知識はないため、推測ですが

    ②foreach (var c int str){}
    おそらく(var c in str)だと思いますが、var c は char型ってことでよろしいでしょうか?

    ③if(debug.Any(n => n == c)){}
    これはint == charが成立した場合に処理をするということですよね
    intとcharが同一であるというのはどういう状態なんでしょうか?
    intが1でcharも1だった場合同一?でもcharに代入されるのはひらがななんですが…わかりませんでした

    ④省略されたのだと思うのですが
    if文のあとはn++を記述するんですよね、記述しなくてもいいのでしょうか?
    でもn++を記述するとcと同一ではなくなるから処理されない??
    このnは何のためのnでしょうか?

    ⑤最後に重要なことで、質問にも書きましたが
     処理する文字は「あ」「と」「ぎ」だけではなく50音に対応、その他、数字も対象に処理する予定です
    StartCoroutine(Cor())のCorの引数に"あとぎ"と書かれていますが
    これでは対応できないのではないでしょうか?
    debug.Anyの部分がわからないので、断定はできませんが…
    ```
    文字ごとに異なる処理をしたいため
    if(arr[n] == "あ")
    {
    Debug.Log("あ");
    }
    if (arr[n] == "と")
    {
    Debug.Log("と");
    }
    if (arr[n] == "ぎ")
    {
    Debug.Log("ぎ");
    }
    と分けて記述しています

    なぜ「あ」と「と」と「ぎ」を代表例にしたかというと
    「ありがとう」という文の最初の文字「あ」
    「ありがとう」の間を飛ばした中間の文字「と」(←「が」でも「う」でもいい)
    「ありがとう」に含まれない文字「ぎ」(←なんでもよかった)
    というデバッグ用に選んだ文字です
    「あとぎ」が含まれていたら処理するわけではないのです。

    長くなり申し訳ありません。
    ToString()については()の記述忘れだと気づけたのでありがたいです

    そして質問には書きませんでしたが、できればラグをなくしたいというだけで
    基本的に処理に対応した文字しか入力されないため
    処理に対応していない文字を飛ばす際にラグがあっても大して困らないので
    その点はあまり気になさらずに回答していただけると助かります
    (要約、ラグは処理しない文字にもあってもいい)

    回答お待ちしております、
    そして質問の閲覧、回答ありがとうございます。

    キャンセル

  • 2020/03/23 06:18

    追記への返信

    しっかり望んだとおり動作しました、ありがとうございます。

    ラムダ式についても調べました
    ラムダ式は短い関数を、関数を作らずに直接書き込むことで省略する機能と解釈しました

    ここからは本来の質問とは、ずれてしまうので回答してくださらなくても構わない部分ですが

    n => n == c の記述の n は結局何なんでしょうか?

    まとめメモ..................................................................................................
    private IE...以下略(string str, string debug, float speed){}
    strにはもともとの文章
    debugには"あとぎ"
    speedは表示速度

    コルーチン処理内
    foreach(var c in str){} で c には str から一文字ずつ代入されて、foreach内の処理が実行される

    foreach内の処理
    if(debug.Any(n => n == c)){} でdebug内に c が存在した場合、if内の処理が実行される

    n は int型変数と定義済み。
    .............................................................................................................................
    Any()が一致するかどうかの判定をするなら
    debug.Any(c)と記述してもいい気はします(もちろんこれでは動作しないであろうことは予想できますが)
    なぜn => n == cという記述になるんでしょうか?

    キャンセル

  • 2020/03/23 07:04

    forでiを使うようなもので、伝統的にnを使う事が多いだけです
    別にa => a == cでもmoji => moji == c でもいいです
    Any(c)と書きたくてもそんな関数がなく、ラムダ式しか引数に渡せないのでラムダ式を渡しています

    キャンセル

  • 2020/03/27 06:01

    お返事遅れて申し訳ないです

    これはそういうものとして覚えておくしかないみたいですね
    ラムダ式について私の理解が足りてないみたいなので、
    今はそういうことで理解しておきます

    ここまでありがとうございました、すごく助かりました!

    キャンセル

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

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