21736


お世話になります。

プレーンテキストで書かれた、下記のようなテーブルを、htmlに変換したいと思っています。  
特に言語は特定しませんが、正規表現の置換などを使用して、徐々にtableタグに落とし込んでいきたいと思っているのですが、流石に途中で頭が破裂しそうになりました。  
じっくりやればできるような気もしますが、できれば良いアイデアをいただければと思います。

単純にpreタグで強引に表示するのはNGです。  
やり方としては、『\n┌』を『\n＜table border="1"＞\n』に置換、『│』を『＜/td＞＜td＞』に  
置換…などといった感じで加工していく方法です。

良い方法をご存知の方、アイデアをいただければ幸いです。

こんな感じのテーブルです。

[code]

    ┌───────────┬───┬───┐
    │ＳＺＡ１２５　　　　　│価格│\1,500│
    ├─────┬─────┴───┴───┴──────────────────────────────┐
    │出力名称　│名称　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    ├─────┼────────────────────────────────────────────┤
    │別名１　　│Ａとか　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    ├─────┼────────────────────────────────────────────┤
    │別名２　　│Ｂとか　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    ├─┬───┴────────────────────────────────────────────┤
    │追│　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    │加│　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    │内│　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    │容│　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　│
    ├─┴────────────────────────────────────────────────┤
    │┌────────────────────────────────────────────────┐│
    ││　　　　　メニュー　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　││
    │├─────────────────────┬─┬───┬────────────────────┤│
    ││メイン　　　　　　　　　　　　　　　　　　│Ａ│　　１│パスタ　　　　　　　　　　　　　　　　  ││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　２│ラザニア　　　　　　　　　　　　　　　　││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　３│カレーライス　　　　　　　　　　　　　　││
    │├─────────────────────┼─┼───┼────────────────────┤│
    ││セット　　　　　　　　　　　　　　　　　　│Ｂ│　　１│サラダセット　　　　　　　　　　　　　　││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　２│コーヒーセット　　　　　　　　　　　　　││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　３│食後のデザートセット　　　　　　　　　　││
    │├─────────────────────┼─┼───┼────────────────────┤│
    ││大盛りサービス　　　　　　　　　　　　　　│Ｃ│　　１│ノーマル　　　　　　　　　　　　　　　　││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　２│ラージライス　　　　　　　　　　　　　　││
    ││　　　　　　　　　　　　　　　　　　　　　│　├───┼────────────────────┤│
    ││　　　　　　　　　　　　　　　　　　　　　│　│　　３│ハーフ＆ハーフ　　　　　　　　　　　　　││
    │└─────────────────────┴─┴───┴────────────────────┘│
    └──────────────────────────────────────────────────┘
    
[/code]

完全にとはいかなくても、八割くらい近づけたいです。  
よろしくお願いします。


CC BY-SA 3.0
2016-02-03T07:43:03.947
21655
2016-02-05T05:48:30.190
2016-02-04T01:13:12.310
4236
9374
question
html アルゴリズム テキストファイル
罫線で書かれたテーブルをhtmlに変換したいが…


単純な置換では難しいです。

表の構造があらかじめ決まっている(行の区切りの回数を数えることでなんのデータが入っているか決定できる)場合は、上から1行ずつ読み込んで

  * `|`を項目の区切り
  * `適当な長さの`──`の連続を行の切り替わり

で判定して各セルのデータを拾っていき、最終的に改めてHTMLの表として再構築するのがよいでしょう。

表の構造が決まっていない場合(罫線で構成された任意の表をHTMLにしたい場合)、入れ子の表の判定であるとか、各項目の幅を判定してcolspanを適切に設定する、とか考える事が格段に増えるのでだいぶ面倒になります。サンプルデータのようにイレギュラーな幅のセルまで反映するとなると一筋縄ではいきません。


CC BY-SA 3.0
2016-02-03T11:49:38.140
21669
2016-02-03T11:49:38.140
5793
21655
answer


`colspan`程度なら、以下のように割と簡単に変換できますが、`rowspan`と表のネストにまともに対応するのは手間が掛かりそうです。

[code]

    # -*- mode: ruby; encoding: utf-8 -*-
    class AATableParser
      def to_html(src)
        buf = []
        buf.push '<table border="1">'
        buf.push '<col width="32pt">'
        src.rstrip.split(/\r?\n/).each {|line|
          unless line.empty? or line.include?('─')
            buf.push parse_row(line)
          end
        }
        buf.push '</table>'
        buf.join("\n")
      end
      private
      def parse_row(line)
        buf = []
        buf.push '<tr>'
        is_first = true
        cur = 1
        line.split(//u).each {|c|
          case c
          when /│/
            idx = line.index('│', cur)
            if idx != nil
              colspan = idx + 1 - cur
              if colspan > 1
                td = %Q|<td colspan="#{colspan}">|
                buf.push is_first ? td : '</td>' + td
                is_first = false
              end
              cur = idx + 1
            end
          when /　/
          else
            buf.push c
          end
        }
        buf.push '</td>'
        buf.push '</tr>'
        buf.join('')
      end
    end
    
    def main
      src = ARGV[0]
      if File.exist?(src)
          parser = AATableParser.new
          buf    = parser.to_html(File.read(src))
          outf = open(src + '.html', "wb")
          outf.puts(buf)
          outf.close()
      else
        puts src
        puts 'No such file'
      end
    end
    main
    
[/code]

[code]

    <table border="1">
    <col width="32pt">
    <tr><td colspan="12">ＳＺＡ１２５</td><td colspan="4">価格</td><td colspan="7">\1,500</td></tr>
    <tr><td colspan="6">出力名称</td><td colspan="45">名称</td></tr>
    <tr><td colspan="6">別名１</td><td colspan="45">Ａとか</td></tr>
    <tr><td colspan="6">別名２</td><td colspan="45">Ｂとか</td></tr>
    <tr><td colspan="2">追</td><td colspan="49"></td></tr>
    <tr><td colspan="2">加</td><td colspan="49"></td></tr>
    <tr><td colspan="2">内</td><td colspan="49"></td></tr>
    <tr><td colspan="2">容</td><td colspan="49"></td></tr>
    <tr><td colspan="51">メニュー</td></tr>
    <tr><td colspan="22">メイン</td><td colspan="2">Ａ</td><td colspan="4">１</td><td colspan="23">パスタ</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">２</td><td colspan="23">ラザニア</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">３</td><td colspan="23">カレーライス</td></tr>
    <tr><td colspan="22">セット</td><td colspan="2">Ｂ</td><td colspan="4">１</td><td colspan="23">サラダセット</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">２</td><td colspan="23">コーヒーセット</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">３</td><td colspan="23">食後のデザートセット</td></tr>
    <tr><td colspan="22">大盛りサービス</td><td colspan="2">Ｃ</td><td colspan="4">１</td><td colspan="23">ノーマル</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">２</td><td colspan="23">ラージライス</td></tr>
    <tr><td colspan="22"></td><td colspan="2"></td><td colspan="4">３</td><td colspan="23">ハーフ＆ハーフ</td></tr>
    </table>
    
[/code]


CC BY-SA 3.0
2016-02-05T05:48:30.190
21736
2016-02-05T05:48:30.190
46
21655
answer