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

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

ただいまの
回答率

90.34%

  • Ruby

    8191questions

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

  • CSV

    709questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • XML

    691questions

    XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

長文テキストから情報を取得したい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 575

yuki_90453

score 96

メール受信時に内容を解析し、情報を取得したいと考えています。メールはテキストメールでありHTML形式ではございません。
下記のメールから商品番号、サイズ、カラー、個数を取得したいと考えています。

(省略)
---------------------------------------------------------------------
[受注番号] 000000-20170205-0000000
[日時]     2017-02-05 00:00:00
[注文者]   名前 太郎 (ナマエ タロウ) 様
          〒123-0000 東京都
          (TEL) 090-0000-4444

[支払方法] クレジット
[ポイント利用] 1000
[配送方法] 郵便
[配送日時指定]


[備考]
●備考
---------------------------------------------------------------------
[ショップ名]   ***********
==========
[送付先]   名前 太郎 (ナマエ タロウ) 様
          〒123-0000 東京都
          (TEL) 090-0000-4444
[商品]
商品名(商品番号)
サイズ:XL
カラー:ブルー
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
----------
商品名(商品番号)
サイズ:XL
カラー:レッド
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
----------
商品名(商品番号)
サイズ:XL
カラー:グリーン
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
*********************************************************************
小計     18,0000(円)
送料     0(円)  離島・一部地域では別途料金が必要な場合があります
---------------------------------------------------
合計     18,0000(円)
---------------------------------------------------------------------
今回のお買い物で獲得するポイント 660
---------------------------------------------------------------------
*消費税について
 消費税率      8%
 消費税計算順序   1商品毎に消費税計算
 1円未満消費税端数 切り捨て
---------------------------------------------------------------------
(省略)

質問

正規表現では複数行や、ここ〜ここまでといった指定方法が難しいかと思います。
正規表現以外の方法でかんたんに取得する方法はないでしょうか?

備考

使用言語 Ruby
メールの容量は5,6KBぐらいの量になります。
送信者側のフォーマットは決まっておりますので、受信者側で解析、変換したいと考えております。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+1

別に複雑な正規表現を使う必要は無く、「見出しが含まれる」くらいでいいです。
1行ずつ読みながら、見出しがあればそこからデータを取得します。
ぜんぜん難しくも、面倒でもないです。簡単です。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/06 18:59

    each_lineというのがあると知りませんでした、取り急ぎありがとうございます。

    キャンセル

+1

a.rb

FILE_NAME = 'data.txt'
START_ITEM = 1
IN_ITEM = 2
SEP_ITEM = 3
END_ITEM = 0

def parse_file(file_name)
  lines = File.readlines(file_name)
  parse_lines(lines)
end

def parse_lines(lines)
  items = []
  status = nil
  item_block = []
  lines.each do |line|
    status = stat_machine(line.chomp, status)
    if status == SEP_ITEM || status == END_ITEM
      items << parse_block(item_block)
      item_block = []
    elsif status == IN_ITEM
      item_block << line
    end
  end
  items
end

def stat_machine(line, status)
  if status.nil?
    return START_ITEM if line == '[商品]'
  elsif status == START_ITEM || status == IN_ITEM || status == SEP_ITEM
    return SEP_ITEM if line == '----------'
    return END_ITEM if line == '*********************************************************************'
    return IN_ITEM
  end
  nil
end

def parse_block(item_block)
  headers = item_block[0].match(/(.*)\((.*)\)/)
  size = color = option = price = count = point = nil
  item_block.shift
  item_block.each do |line|
    size   = line.match(/サイズ:(.*)/)[1]       if line.start_with?('サイズ:')
    color  = line.match(/カラー:(.*)/)[1]       if line.start_with?('カラー:')
    option = line.match(/※オプション:(.*)/)[1] if line.start_with?('※オプション:')
    price, count = line.gsub(',', '').match(/価格  (\d+)\(円\) x (\d+)\(個\) = (\d+)\(円\)/).captures if line.start_with?('価格')
    point  = line.match(/獲得ポイント(\d*)/)[1]  if line.start_with?('獲得ポイント')
  end

  {
    name: headers[1],
    code: headers[2],
    size: size,
    color: color,
    price: price.to_i,
    count: count.to_i,
    option: option,
    point: point.to_i
  }
end

items = parse_file(FILE_NAME)
items.each { |item| puts item }

data.txt

(省略)
---------------------------------------------------------------------
[受注番号] 000000-20170205-0000000
[日時]     2017-02-05 00:00:00
[注文者]   名前 太郎 (ナマエ タロウ) 様
          〒123-0000 東京都
          (TEL) 090-0000-4444

[支払方法] クレジット
[ポイント利用] 1000
[配送方法] 郵便
[配送日時指定]


[備考]
●備考
---------------------------------------------------------------------
[ショップ名]   ***********
==========
[送付先]   名前 太郎 (ナマエ タロウ) 様
          〒123-0000 東京都
          (TEL) 090-0000-4444
[商品]
商品A(000-1234)
サイズ:XL
カラー:ブルー
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
----------
商品A(001-1234)
サイズ:XL
カラー:レッド
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
----------
商品A(002-1234)
サイズ:XL
カラー:グリーン
※オプション:無し
価格  6,0000(円) x 1(個) = 6,0000(円)   (税込、送料込)
獲得ポイント660
*********************************************************************
小計     18,0000(円)
送料     0(円)  離島・一部地域では別途料金が必要な場合があります
---------------------------------------------------
合計     18,0000(円)
---------------------------------------------------------------------
今回のお買い物で獲得するポイント 660
---------------------------------------------------------------------
*消費税について
 消費税率      8%
 消費税計算順序   1商品毎に消費税計算
 1円未満消費税端数 切り捨て
---------------------------------------------------------------------
(省略)

実行結果

$ ruby a.rb
{:name=>"商品A", :code=>"000-1234", :size=>"XL", :color=>"ブルー", :price=>60000, :count=>1, :option=>"無し", :point=>660}
{:name=>"商品A", :code=>"001-1234", :size=>"XL", :color=>"レッド", :price=>60000, :count=>1, :option=>"無し", :point=>660}
{:name=>"商品A", :code=>"002-1234", :size=>"XL", :color=>"グリーン", :price=>60000, :count=>1, :option=>"無し", :point=>660}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

checkベストアンサー

0

プログラムは示せませんが戦略だけ書いておきます。

基本的には1行ずつ処理することになると思います。
その行にキーワードが含まれていれば解析することで対応することになるでしょう。

サイズとカラーは固定の文字列のようなので、行に含まれていればコロン(:)以降の文字列を取得すれば出来ますが、商品番号は「商品名」が都度変わると思うのでちょっと面倒ですね。商品名のリストを持っておいて比較しても良いかもしれませんが、リストが膨大だったり不定期に更新されたりするとそれに対応する必要があるので処理が面倒になります。
もし、

商品名:実際の商品名(商品番号)

と固定の文字列(商品名:)が頭に必ず入るのならサイズやカラーと同じになるので楽なんですけどね。

それと、個数は価格のところにしか無いようなので、価格を含む行を探して、「x」から「(個)」の間の数字を取ってくることで対応できるかと。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/06 18:59

    each_lineというのがあると知りませんでした、取り急ぎありがとうございます。

    キャンセル

0

#encoding : utf-8
mail = open("メールテスト.txt", &:read).encode("UTF-8").scan(%r|商品名(.+)\nサイズ(.+)\nカラー(.+)\n※オプション:(.+)\n価格(.+)\n|)
mail = mail.transpose
item = mail[0]
size = mail[1]
color = mail[2]
num = mail[4]
mail.clear
item.map!{|e| e.gsub(/\(|\)/, "")}
size.map!{|e| e.gsub(":", "")}
color.map!{|e| e.gsub(":", "")}
num.map!{|e| e.scan(%r|\d+?\(個\)|).map{|ee| ee.gsub("(個)", "")}}.flatten!
mail << item
mail << size
mail << color
mail << num
mail = mail.transpose
mail.each do |element|
  puts "#{element[0]}\s#{element[1]}\s#{element[2]}\s#{element[3]}"
end


実行結果例

商品番号 XL ブルー 1
商品番号 XL レッド 1
商品番号 XL グリーン 1


今更ですが考えてみました。
正規表現以外の方法でという質問でしたが正規表現でもここからここまで
みたいなことができるのではと考えた次第です。
openとreadでテキストファイル全体を読み込んで正規表現で該当する部分を抜き出します。
transposeでそれぞれの項目ごとにまとめて、形を整えます。
形を整えたら再びtransposeで商品ごとにして出力します。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/06 22:31

    助かります、ありがとうございます。

    キャンセル

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

  • Ruby

    8191questions

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

  • CSV

    709questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • XML

    691questions

    XMLは仕様の1つで、マークアップ言語群を構築するために使われています。