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

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

ただいまの
回答率

90.62%

  • JavaScript

    15905questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Electron

    191questions

    Electronは、HTML5とNode.jsというWebの技術を用いてデスクトップアプリケーションを作成できるクロスプラットフォームな実行環境です。

【JavaScript】indexOfで特定文字が反応しない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,318

nnahito

score 1689

JavaScriptのindexOfメソッドで、文章の検索を実行しているのですが、
何故か「よという文字だけが反応しません。

「あ「漢「alphaなどはしっかりと開始位置が取得できます。
これはなぜでしょうか…?

perlで言う、http://www.shtml.jp/mojibake/sjis_cgi.htmlの様な現象なのでしょうか?

JavaScriptで、このような事例が、しかも「よで起こるということを聴いたことがなく、困惑しております。
ご存じの方がいらっしゃいましたら、ご教示ください。
よろしくお願いいたします。

 追記

テンパりすぎて、コードの掲載などを失念しておりました。
追記いたします。


【やりたいこと】
文章の入った変数から、
開始文字から終了文字までを抜き出したい。


開始文字:「
終了文字:」
文章:「会話文1」地の文「会話文2」
理想結果:「会話文1」「会話文2」


【利用環境】

  • MacOS X Yosemite
  • FireFox 50.0.1
  • CodeMirror 5.22.1
  • Electron v1.4.12 

【手順】
Electronウインドウ上のCodeMirrorを反映させたTextAreaから文字列を取得。
その中から会話文をのみを取得。

【状況】
Electronウインドウ上のCodeMirrorを反映させたTextAreaから文字列を取得はできており、変数に格納できている。
開始文字列(「)と、終了文字列(」)も取得できている。

それらを以下のオリジナルの関数に投げ、配列として結果を返したい。

なお、

  • text:全文章
  • from_text:開始文字列
  • to_text:終了文字列

としています。

function createLinesCount(text, from_text, to_text){
        var start = 0;                                                    // 検索開始位置
        var end = 0;                                                        // 検索終了位置
        var lines = [];                                                    // 抜き出した文字列

        // 検索終了文字が指定されていなければ、改行コードを終了文字にする
        if ( to_text == "" ) to_text = "\n";

        while( 1 ){
            // 検索開始位置を取得
            start = text.indexOf(from_text, start);

            if ( start === -1 ) break;

            // 検索終了位置を取得
            end = start + to_text.length;
            end = text.indexOf(to_text, end) + to_text.length;

            // 文字の抜き出し
            var line = text.substring(start, end);

            // 抜き出した文字列を配列に追加
            lines[lines.length] = line;

            start = start + end;

        }

        return lines;

    }

【結果】
●全文章
「あ」
「漢」
「よ」
「alpha」

●開始文字列

●終了文字列

●取得結果
イメージ説明

よろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • carimatics

    2017/01/11 23:39

    コードを掲載してください。また、そのコードにおける期待した結果と実際の結果も併せて掲載してください。

    キャンセル

  • nnahito

    2017/01/11 23:58

    申し訳ありません。情報を追加しました。

    キャンセル

回答 2

+3

 String.prototype.indexOf

問題なく動きましたので、現象を再現可能なコードを開示する事をお勧めします。

'use strict';
console.log('「よ」'.indexOf('「よ')); // 0

 残存する問題点

下記コードは質問文のコードをそのまま使用したものです。

質問の本題部分は ikedas さんの回答で解決できていますが、まだ問題が残っているように思います。

ローカル変数 lines

var lines = [];  // 抜き出した文字列

区切り文字が改行であるとは限らない為、変数名 lines に違和感があります。
質問文のケースにあてはめても改行を含まない文字列に対して処理を行う事が可能です。

console.log(createLinesCount('「あ」「漢」「alpha」', '「', '」')); // ["「あ」","「漢」","「alpha」"]

第三引数(検索終了文字)の省略

// 検索終了文字が指定されていなければ、改行コードを終了文字にする
if ( to_text == "" ) to_text = "\n";

to_text が指定されなかった場合、undefined として評価されますが、undefined == "" は「偽」なのでこの条件式は正しく機能しません。
従って、第三引数を省略した場合に to_text.length の部分で「TypeError 例外」が発生してしまいます。

createLinesCount('「あ」\n「漢」\n「よ」\n「alpha」', '「');  // TypeError: Cannot read property 'length' of undefined

検索終了文字列が持つからないと無限ループする

// 検索終了位置を取得
end = start + from_text.length;
end = text.indexOf(to_text, end) + to_text.length;

検索終了文字列('to_text')が見つからなかった時の配慮がありません。
仮に次のコードを実行した場合、

createLinesCount('「あ\n「漢\n「よ\n「alpha', '「', '」'));     // "」" が見つからないので無限ループしてしまう

検索終了文字列('"」"')が見つからない為に text.indexOf(to_text, end) の評価値が -1 となり、to_text.length は 1 なので end が 0 にリセットされます。
すると、初めから検索をやり直すことになるので while 文が無限ループしてしまいます。

while(1)

while( 1 ){

while (1) は無限ループになるリスクがある為、可能な限りループ継続条件となる条件式を与えてやるのが好ましいと思います。
前述の無限ループもwhile条件を見直すことで回避する事が可能です。

 修正コード (String#indexOf版)

上記問題を修正したコードがこちら。

'use strict';
function extractFromString(targetString, startString, endString){ // 検索対象文字列, 検索開始文字列, 検索終了文字列
  // 全ての引数を String 型に変換する
  targetString = String(targetString);
  startString = String(startString);
  endString = arguments.length > 2 ? String(endString) : '\n'; // 検索終了文字が指定されていなければ、改行コードを終了文字にする

  var startStringLength = startString.length, // 検索開始文字列の文字数
      endStringLength = endString.length,     // 検索終了文字列の文字数
      extractedStrings = [],                  // 抜き出した文字列リスト
      startPosition,
      endPosition;

  do {
    startPosition = targetString.indexOf(startString, startPosition);

    if (startPosition !== -1) {
      endPosition = targetString.indexOf(endString, startPosition + startStringLength);

      if (endPosition !== -1) {
        extractedStrings.push(targetString.slice(startPosition, endPosition + 1));
        startPosition = endPosition + endStringLength;
      }
    }
  } while (startPosition !== -1 && endPosition !== -1);

  return extractedStrings;
}

console.log(extractFromString('「あ」\n「漢」\n「よ」\n「alpha」', '「', '」')); // ["「あ」", "「漢」", "「よ」", "「alpha」"]
console.log(extractFromString('「あ」「漢」「よ」「alpha」', '「', '」'));       // ["「あ」", "「漢」", "「よ」", "「alpha」"]
console.log(extractFromString('「あ」\n「漢」\n「よ」\n「alpha」', '「'));      // ["「あ」\n", "「漢」\n", "「よ」\n"]

 修正コード (正規表現版)

正規表現を利用するとスマートに実装できます。

function extractFromString2 (targetString, startString, endString) {
  // 正規表現化する為に文字列をエスケープする
  startString = String(startString).replace(/(?=[$()*+\-.?\[]^{|}])/g, '\\');
  endString = arguments.length > 2 ? String(endString).replace(/(?=[$()*+\-.?\[]^{|}])/g, '\\') : '\n';

  return String(targetString).match(new RegExp(startString + '[^' + endString + ']*' + endString, 'g'));
}

console.log(extractFromString2('「あ」\n「漢」\n「よ」\n「alpha」', '「', '」')); // ["「あ」", "「漢」", "「よ」", "「alpha」"]
console.log(extractFromString2('「あ」「漢」「よ」「alpha」', '「', '」'));       // ["「あ」", "「漢」", "「よ」", "「alpha」"]
console.log(extractFromString2('「あ」\n「漢」\n「よ」\n「alpha」', '「'));      // ["「あ」\n", "「漢」\n", "「よ」\n"]

Re: nnahito さん

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/11 23:57

    申し訳ありません。
    情報を追加しました。

    キャンセル

  • 2017/01/12 12:45

    To: nnahito さん
    質問はクローズされていますが、まだ問題が残っているようなので親記事に追記しました。

    キャンセル

checkベストアンサー

+1

start = start + end;

ここは

start = end;

になるのでは?

ちなみに、今回の例では問題ないですが、

end = start + to_text.length;

end = start + from_text.length;

だと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/01/12 00:22

    ご回答ありがとうございます。
    修正したら治りました……お恥ずかしい……
    たすかりました、ありがとうございます!

    キャンセル

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

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

関連した質問

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

  • JavaScript

    15905questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Electron

    191questions

    Electronは、HTML5とNode.jsというWebの技術を用いてデスクトップアプリケーションを作成できるクロスプラットフォームな実行環境です。