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

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

ただいまの
回答率

90.48%

  • HTML

    9299questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • Ruby

    7958questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Rubyの正規表現で特定のclassを持つ文字だけmatchさせたいです。

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 2,151
退会済みユーザー

退会済みユーザー

<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span><span class="red">(未読:1件)</span>

<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span>

<span class="red"</span>を持つグループだけを取得し、"欲しい文字"と(未読: x件)の部分を表示させたいのですが、どういった正規表現が正しいのでしょうか?
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

+4

学習目的でなければ、正規表現ではなく 各言語にあるパーサ ライブラリを利用しましょう

Ruby であれば、nokogiri がそのひとつとして挙げられるでしょう

gem install nokogiri

例示されたコードをindex.html として保存しました

require 'nokogiri'

file = File.read(File.expand_path('./index.html'))
html = Nokogiri::HTML(file)

p html.css('span.red').map { |element| element.text }
# => ["(未読:1件)"]

## Links

Ruby ドキュメント
Tutorials - Nokogiri 鋸
Nokogiri の基本(翻訳版) - Engine Yard Blog
More Resources - Nokogiri 鋸
Rubyによるクローラー開発技法 巡回・解析機能の実装と21の運用例

このNokogiri ライブラリを利用していて、Web ページの情報収集に向くMechanize というライブラリもあるようです

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+2

得られる HTML が間違いなく一行にお書きの要素が入っており、 class 要素の直後に > が来ていることを前提とします。
<span class="red"> が入っている行を取得するのは k.tada さんのやり方で良いと思います。

target = <<-EOF
<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span><span class="red">(未読:1件)</span>
<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span>
EOF

target.lines.select { |line| line.include?('class="red"') }
これにより文字列
<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span><span class="red">(未読:1件)</span>

が含まれた配列が取得出来ました。
次にこの文字列から"欲しい文字"と"(未読: x件)"を取得するときに 正規表現を使う とすると
/class="listName">([^<]+).+class="red">([^<]+)/
で良いと思います。

合わせると

target.lines.select { |line| line.include?('class="red"') }.map do |line|
  line.match(/class="listName">([^<]+).+class="red">([^<]+)/).to_a[1..-1]
end
#=> [["欲しい文字", "(未読:1件)"]]

となります。

しかし。
本当に、必ずそのような HTML が得られるでしょうか?
HTML に改行が入っていても Web ブラウザの解釈は同じになります。タグ内の要素が前後していてもやはり同じ解釈になります。
そのような HTML というものに対して正規表現で対応するのは、スイスアーミーナイフでマグロを捌こうとするようなもので、正直言って相応しくないと思います。

ということで、 HTML を処理する場合には HTML パーサを使いましょう。 gouf さんが示した Nokogiri や、Ruby 標準ライブラリの REXML が使えます(ただし今回のような HTML の一部だけに対しては REXML だとパース出来ません)。

では Nokogiri を使ってみます。
残念ながら元の HTML が a タグも span タグも並列に入っており、それらを覆う div タグが入っていないので、すこし面倒になります。具体的には <span class="red"> を選択した後に兄要素を取得する必要があります。 XPath ならば preceding-sibling を使います。 CSS では選択不可能でした(CSS4 で可能になるそうですが)。

HTML を少し変更して、それを対象にして実行します。

target = <<-EOF
<a href="/list/timeline/26527/latest" class="listName">欲しい文字1</a><span class="date">(登録日:2014-12-03)</span><span class="red">(未読:3件)</span>
<a href="/list/timeline/26527/latest" class="listName">欲しい文字2</a><span class="date">(登録日:2014-12-04)</span>
<a href="/list/timeline/26527/latest" class="listName">欲しい文字3</a><span class="date">(登録日:2014-12-05)</span><span class="red">(未読:5件)</span>
EOF

doc = Nokogiri::HTML.parse(target)
doc.xpath('//span[@class="red"]').map do |span|
  [span.xpath('preceding-sibling::a[1]').text, span.text]
end
#=> [["欲しい文字1", "(未読:3件)"], ["欲しい文字3", "(未読:5件)"]]

あとは取得出来た配列の要素を何らかの方法で表示させれば良いでしょう。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/02/19 08:15

    わかりやすかったです。回答ありがとうございます!

    キャンセル

+1

ざっと書いたので雑で申し訳ないですが、
下記のようにして、class="red"を含む行のみ抽出し、HTMLタグの中の文字のみを取り出して配列にしてみました。
あとはその配列から任意の項目を取り出してください。

target = <<-EOF
<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span><span class="red">(未読:1件)</span>
<a href="/list/timeline/26527/latest" class="listName">欲しい文字</a><span class="date">(登録日:2014-12-03)</span>
EOF

target.lines.select {|l| l.include?('class="red"')}.each {|s| p s.scan(/>([^<]+)</) } # [["欲しい文字"], ["(登録日:2014-12-03)"], ["(未読:1件)"]]

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

関連した質問

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

  • HTML

    9299questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

  • Ruby

    7958questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。