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

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

ただいまの
回答率

90.51%

  • PHP

    20395questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    16476questions

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

  • jQuery

    6726questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • 正規表現

    798questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

ルビの振られたHTMLからルビを無視して文字列をマッチさせたい

解決済

回答 5

投稿 編集

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

前提・実現したいこと

php か jQeury のどちらかで実現できる方法、もしくは両方で実現できる方法を探しています。

ルビのある文字文字列をハイライトしたいです。

サイトを運営しております。自身のサーバーにルビ情報を含んだテキストファイルがあり、それを php で読み込んで表示しております。

この文章に対して指定した部分をハイライトにしたいです。たとえば「腰を抜かしたことがある」の部分にハイライトを施すために以下のように書き換えたいです。

「腰を抜かしたことがある」の部分だけ取り出すとこう

<span class=highlight></span></rb><rp></rp><rt>こし</rt><rp></rp></ruby><span class=highlight></span><ruby><rb><span class=highlight></span></rb><rp></rp><rt></rt><rp></rp></ruby><span class=highlight>かした事がある。</span>

ルビのふりがなと(かっこ)以外を highlight という名前の class で囲んでいます。

「腰を抜かしたことがある」の部分は自身の管理するデータベースに保存してあります。

発生している問題

</rb><rp></rp><rt>こし</rt><rp></rp></ruby><ruby><rb></rb><rp></rp><rt></rt><rp></rp></ruby>かした事がある。

上の文章(ルビ付きの文章)がデーターベースにあれば自分でもphp や jQuery の正規表現などで置換して span class で囲うことができます。しかし、データーベースにはルビが取り除かれた文章しかありません。

腰を抜かしたことがある

正規表現をうまく使えばできるような気もするのですが、いい方法が思いつきません。
何かいいアイデアがあれば教えていただきたいです。

よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • Zuishin

    2017/03/26 08:45

    あと、例えば ABC という文字列があったとして、AB がハイライト指定、BC がルビ指定の場合、または AB がルビ指定、BC がハイライト指定の場合は ABC 全体をハイライトしてもいいのですか?

    キャンセル

  • totomaru483838

    2017/03/26 08:48

    1 → ハイライトのない文章(ルビあり)。2 → ハイライトしたい箇所の文字情報(ルビなし)この二つの情報を持っています。2は1の一部分です。ですが1がルビありなのに対して、2はルビがないためマッチのさせ方が分からないという質問です。

    キャンセル

  • Zuishin

    2017/03/26 08:57

    わかりました。説明だけいただいたので、こちらもアルゴリズムだけ。まず双方の文章からルビもハイライトもない文章を取り出します。そして、ルビとハイライトの位置を対応させます。例えば、ルビを 1、ハイライトを 2、どちらもあるものを 3 とし、「腰を抜かしたことがある」のうち、「腰」「抜」にルビが振られ、「腰を抜かした」までがハイライトだとすると、ルビハイライト情報は「3232200000」となります。3 の連続部分をルビとハイライトで囲み、2 の連続部分をハイライトで囲めば完成ですが、ルビを振る漢字が連続している場合があるので、この情報だけではなくルビ情報も参照します。以上です。

    キャンセル

回答 5

+1

アイデアだけを記述します

HTMLタグなし文字列 -> ハイライト文章置換 -> ルビ文字置換 して完成させる方法です

A: 置換作業用に ルビ対象文字 と <ruby>タグ文字列 の取得

  1. オリジナルのHTMLから正規表現を使って <ruby>タグ文字列 を取得する
  2. <ruby>タグ文字列 から正規表現を使って <rb>タグ内の ルビ対象文字 を取得する

B: ハイライト文章・ルビ対象文字 の置換

  1. オリジナルHTMLから タグを取り除いた文字列 を取得する
  2. タグを取り除いた文字列 の中の ハイライト文章を <span class="highlight">ハイライト文章</span> で置換する
  3. さらに ルビ対象文字 を <ruby>タグ文字列 で置換する

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

 課題

技術的には可能ですが、要件だけ出して「教えてください」といえる難易度の問題ではないように思います。

  1. <span>あいう</span><span>えお</span> に対して検索語「あいうえお」がマッチしなければならない(MUST)
  2. <span>あいう</span><span>えお</span> に対して検索語「うえ」がマッチしなければならない(MUST)
  3. <span title="すくりぷと">Script</span> に対して検索語「すくりぷと」がマッチしてはならない(MUST NOT)
  4. <h1>サンプル</h1><p>これはテストです。</p> に対して「検索語「サンプルこれはテストです。」がマッチしてはならない(MUST NOT)

上記例題は次のDOMを出力する事を期待します。

  1.  <span><mark class="highlight">あいう</mark></span><span><mark class="highlight">えお</mark></span> もしくは <mark class="highlight"><span>あいう</span><span>えお</span></mark>
  2. <span>あい<mark class="highlight">う</mark></span><span><mark class="highlight">え</mark>お</span>
  3. マッチしない
  4. マッチしない

※1. は後者がすっきりしていますが、2. の処理を入れることを踏まえると前者の方がコードを書きやすいかもしれません。

 実装案

正規表現でタグの対応関係、インラインボックスのタグだけ抽出する実装は複雑化してしまいます。
以下にDOM API で実装する手順を書きます。

  1. document.evaluate で検索語の1文字目となるテキストノードを検索(参考: https://teratail.com/questions/31198)
  2. テキストノード内の文字列を1文字ずつ検索し、テキストノード内に検索語の前方一致語区を発見したら、createElement で mark 要素を生成し、appendChild でテキストノードを挿入後に  replaceChild で置換する
  3. テキストノード内に検索語が部分一致で見つかったら処理を終了し、前方一致で見つかったら 4. へ進む
  4. element.parentNode で親要素を参照し、computedStyle の display プロパティが inline もしくは inline-block の場合に 5. へ進み、そうでないなら終了する
  5.  element.nextSibling が存在しないなら 4.へ戻り、存在するなら element.nextSibling を参照して 6. へ進む
  6. element.nodeType がテキストノードならまだマッチしていない検索語を対象にして 3. へ戻り、要素ノードなら 7. へ進む
  7.  element.firstChild の nodeType がテキストノードになるまで firstChild を参照し続け、テキストノードを発見したら 6. へ戻り、 firstChild が null になるまで参照し続けたら終了する

コメントノードの読み飛ばし等、細かな例外処理はありますが、大まかにはこんな流れで実装可能だと思います。

Re: totomaru483838 さん

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

考えてみました。

まず、検索対象のテキストだけ取り出します。だいたいこんなコードになると思います。

var str = '<p><ruby><rb>親譲</rb><rp>(</rp><rt>おやゆず</rt><rp>)</rp></ruby>りの<ruby><rb>無鉄砲</rb><rp>(</rp><rt>むてっぽう</rt><rp>)</rp></ruby>で小供の時から損ばかりしている。...';

var skippedElements = Array('RP', 'RT');
var textNodes = Array();
function getTextNodes(node) {
    if (node.nodeName && skippedElements.includes(node.nodeName.toUpperCase()))
        ;
    else if (node.nodeType === 1)
        node.childNodes.forEach(function(e){getTextNodes(e)});
    else if (node.nodeType === 3)
        textNodes.push(node);
}

var nodes = $.parseHTML(str);
nodes.forEach(function(node){
    getTextNodes(node);
});

var text = textNodes.map(function(node){node.nodeValue}).join('');


検索対象になるテキストがtextに、それに対応するDOMのテキストノードの配列がtextNodesに入っています。概念的に書くと、つぎのようになっているはずです。

textNodes = [Text("親譲"), Text("りの"), Text("無鉄砲"), Text("で小供の時から損ばかりしている。...")];
text = "親譲りの無鉄砲で小供の時から損ばかりしている。...";

なお、上でTextで示したオブジェクトは、元の文書に含まれるテキストノードそのものです (javascriptのメソッドではありません)。

ここからは具体的なコードは書きませんが、次のようにすればいいと思います。

"損ばかり"を見つけてハイライトしたいとします。textでこの文字列を探すと、14番目の文字 (最初を0番目とする) から始まる4文字が一致します。

textNodesの要素を最初から順に見ていくと、文字数が2、2、3、…ですから、全体で14番目の文字は、3番目 (最初を0番目とする) の要素の7番目の文字です (14 - (2 + 2 + 3))。

そこで、テキストノードを次のような複数のノードで置換します。

Text("で小供の時から損ばかりしている。...")Text("で小供の時から"), Element('<span class="highlight">損ばかり</span>'), Text("している。...")
//   (最初の7文字)       (4文字、<span>要素でラップ)            (残り)

置換するものは、前述のとおり元のDOMツリーのテキストノードです。ですから、元のDOMツリーの指定の場所をハイライトできます。

上の例ではハイライトの範囲がひとつのテキストノードだけですが、複数のノードにまたがる場合もあります。また各ノードのテキストの全体がハイライト範囲になる場合も、一部だけがなる場合もあります (例えば「親譲り」をハイライトさせるには、「親譲」のノードのテキスト全体と「りの」のノードのテキストの一部を、それぞれハイライトしたノードに置き換える必要があります)。多少複雑ではありますが、場合分けをしっかり整理してからコードを書けば、できないことはないです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

checkベストアンサー

0

こういうことでしょうか?

rb {
    background-color: rgba(255, 200, 190, 0.3);
    color: red;
    padding: 0.7em 0.5em 0.2em;
}
<p><ruby><rb>親譲</rb><rp></rp><rt>おやゆず</rt><rp></rp></ruby>りの<ruby><rb>無鉄砲</rb><rp></rp><rt>むてっぽう</rt><rp></rp></ruby>で小供の時から損ばかりしている。小学校に居る時分学校の二階から飛び降りて一週間ほど<ruby><rb><span class=highlight></span></rb><rp></rp><rt>こし</rt><rp></rp></ruby><span class=highlight></span><ruby><rb><span class=highlight></span></rb><rp></rp><rt></rt><rp></rp></ruby><span class=highlight>かした事がある。</span>なぜそんな<ruby><rb>無闇</rb><rp></rp><rt>むやみ</rt><rp></rp></ruby>をしたと聞く人があるかも知れぬ。</p>

動くサンプル:https://jsfiddle.net/xgjv9ttf/

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/26 03:30

    ご回答ありがとうございます。質問が言葉足らずだったので追記しました。質問内容を勘違いさせてしまい申し訳ございません。

    キャンセル

  • 2017/03/26 03:55 編集

    「ルビのある文字文字列をハイライトしたい」ではなく「ルビの振られたHTMLからルビを無視して文字列をマッチさせたい」とかかなぁ、日本語って難しい。

    「ハイライト」の対象は例えば「譲り」のようにルビの途中から始まるものもありますか?
    また、同じ文字列が来たら全てハイライト対象にするのでしょうか。

    キャンセル

  • 2017/03/26 07:03

    「譲り」のようにルビの途中から始まるものもあります。
    同じ文字列が来た場合、すべてハイライトしてもいいですし、最初の一か所だけハイライトでも構いません。実現しやすいほうを採用したいと思っています。

    キャンセル

  • 2017/03/26 07:06

    タイトル案を採用させていただきました。ありがとうございます。

    キャンセル

0

追記ありがとうございます。
内容確認しましたが、現状の情報だけでは実現は難しいと思います。
つまり「ハイライトしたい文字列」を「HTMLタグ単位」でプログラム側で把握する必要があります。

「ハイライトしたい部分だけを収めた情報」は自身で管理しているデータベースに格納されているということですが、それを変更することは可能ですか?
私なら、「ハイライトしたい部分だけを収めた情報」のデータ構造を見直します。

具体的には、

1.「ルビはあるけどハイライトのない文章」の行番号を持たせる
2.「HTMLタグ単位」でハイライトしたい単語ごとに分割する

というようなことをします。

以下のような感じですね。

【ルビはあるけどハイライトのない文章】(ルビを<>で記載)

親譲<おやゆず>りの無鉄砲<むてっぽう>で小供の時から損ばかりしている。
小学校に居る時分<じぶん>学校の二階から飛び降りて一週間ほど腰<こし>を抜かした事がある。

【自身のデータベースに存在するデータ】

1/親譲
1/無鉄砲
2/時分
2/腰

これで、プログラム側で「ルビはあるけどハイライトのない文章」のうちどの文字列をハイライトすれば良いかが分かります。
あとはコーディングすることになりますが、すみません、具体的なコードは提示できないのですが手順としてはたとえば以下のようになるかと思います。

1.「ルビはあるけどハイライトのない文章」を1行読み込む
2.1のとき、「現在の行番号」をカウントしてプログラム側で行数を把握する。
3.「自身のデータベースに存在するデータ」のうち2に該当する行番号に関する部分のみを読み込み、ハイライトすべき箇所を把握する(1行目であれば「親譲」、「無鉄砲」のみを読み込む)
4.1で読み込んだ文章のうち、3で把握した箇所をハイライトするよう変更する

というようなイメージになると思います。
回答になっていますでしょうか・・・。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • PHP

    20395questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    16476questions

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

  • jQuery

    6726questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • 正規表現

    798questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。