GrammarlyでLaTeXの原稿の英文校正をしたい(2/2)



https://qiita.com/kondo_koichi/items/bd3cf74f8d491a65fd2a

Pandocを使えばLaTeXをテキストへ変換できるようだ．

https://qiita.com/sky_y/items/80bcd0f353ef5b8980ee

しかし，全てのLaTeXコマンドを対応していないので，LaTeXのソースコードの修正を事前にする必要がある．原稿を書きながらに，常にテキストへの変換は現実的ではない．LaTeXのコマンドを無視して，テキストに変換するプログラムが欲しい．

    $ latex_to_text.rb input.tex output.txt

```latex_to_text.rb
#!/usr/bin/ruby
require 'date'

# debuggin mdoe
verbose=0
input='stdin'
input_fname=''
output='stdout'
output_fname=''

###################################
#  str=str.reject(&:empty?)
###################################

$latex_preamble=[
  '\usepackage',
  '\newcommand', '\newcommand*',
  '\renewcommand', '\renewcommand*',
  '\setlength', '\setlength*'
]

# 特殊キャラクタを置換
$latex_special_chars={
  '~'=>' ', '---'=>'ー', '--'=>'-'
}

# 段落替えコマンド
$latex_par=[
  '\par', '\newpage',
  '\n', '\nn', '\nnn', '\nnnn', '\cbreak'
]

# 引数のないコマンドの置換
$latex_command={
  '\@'=>'', '\,'=>' ', '\quad'=>' ',
  '\{'=>'{', '\}'=>'}',
  "\\'e"=>'é', "\\'a"=>'á', '\`e'=>'è', '\`a'=>'à', '\"e'=>'ë', '\"a'=>'ä',
  '\alpha'=>'α', '\beta'=>'β', '\gamma'=>'γ', '\delta'=>'δ', '\epsilon'=>'ϵ',
  '\zeta'=>'ζ', '\eta'=>'η', '\theta'=>'θ', '\iota'=>'ι', '\kappa'=>'κ',
  '\lambda'=>'λ', '\mu'=>'μ', '\nu'=>'ν', '\xi'=>'ξ', '\pi'=>'π', '\rho'=>'ρ',
  '\sigma'=>'σ', '\tau'=>'τ', '\upsilon'=>'υ', '\phi'=>'ϕ', '\chi'=>'χ',
  '\psi'=>'ψ', '\omega'=>'ω', '\varepsilon'=>'ε', '\vartheta'=>'ϑ',
  '\varrho'=>'ϱ', '\varsigma'=>'ς', '\varphi'=>'φ', '\Gamma'=>'Γ',
  '\Delta'=>'Δ', '\Theta'=>'Θ', '\Lambda'=>'Λ', '\Xi'=>'Ξ', '\Pi'=>'Π',
  '\Sigma'=>'Σ', '\Upsilon'=>'Υ', '\Phi'=>'Φ', '\Psi'=>'Ψ', '\Omega'=>'Ω',
  '\hbar'=>'ℏ', '\partial'=>'∂', '\infty'=>'∞', '\in'=>'∊', '\ni'=>'∍',
  '\simeq'=>'≃', '\pm'=>'±', '\times'=>'×', '\sum'=>'Σ', '\prod'=>'Π',
  '\int'=>'∫', '\sqrt'=>'√', '\top'=>'T', '\mapsto'=>'↦', '\to'=>'→',
  '\rightarrow'=>'→', '\Rightarrow'=>'⇒', '\leftarrow'=>'←',
  '\Leftarrow'=>'⇐', '\le'=>'≤', '\ge'=>'≥',
  '\dots'=>'…', '\ldots'=>'…', '\cdots'=>'…',
  '\cdot'=>'・', '\vdots'=>'⋮', '\ddots'=>'⋱', '\item'=>'---',
  '\centering'=>'', '\hspace'=>'', '\hspace*'=>'', '\vspace'=>'', '\vspace*'=>'',
  '\hrulefill'=>'----------------',
}

# \maketitleに含まれるコマンドと環境
$latex_maketitle_cmd={
  '\title'=>'Title:',
  '\author'=>'Author:',
  '\authorinfo'=>'Author:',
  '\affiliation'=>'Affiliation:',
  '\email'=>'E-mail:',
  '\date'=>'Date:',
  '\group'=>'Activity Group:',
  '\abstract'=>'Abstract:',
  '\keywords'=>'Keywords:'
}

# \maketitleに含まれる環境
$latex_maketitle_env={
  'abstract'=>'Abstract:'
}

# 節など
$latex_section={
  '\chapter'=>'Chapter:',
  '\chapter*'=>'Chapter:',
  '\section'=>'Section:',
  '\section*'=>'Section:',
  '\subsection'=>'Subsection:',
  '\subsection*'=>'Subsection:',
  '\subsubsection'=>'Subsubsection:',
  '\subsubsection*'=>'Subsubsection:',
  '\Chapter'=>'Chapter:',
  '\Section'=>'Section:',
  '\Subsection'=>'Subsection:',
  '\Subsubsection'=>'Subsubsection:',
}

# キャプションなど
$latex_caption={
  '\caption'=>'Caption:',
  '\includegraphics'=>'Graphics:',
  '\acknowledgments'=>'Acknowledgments:',
  '\references'=>'References:',
  '\appendix'=>'Appendix:',
}

# テキストなど
$latex_text=[
  '\text', '\bm', '\mathcal', '\mathbb',
  '\em' '\embox', '\mathembox', '\graybox', '\mathgraybox',
  '\darkgraybox', '\mathdarkgraybox', '\lightgraybox', '\mathlightgraybox',
  '\redbox', '\mathredbox', '\greenbox', '\mathgreenbox',
  '\darkgreenbox', '\mathdarkgreenbox', '\yellowbox', '\mathyellowbox',
  '\darkyellowbox', '\mathdarkyellowbox'
]

# 文献など
$latex_bibitem={
  'thebibliography'=>'Bibliography:',
}

# 箇条書きなど
$latex_item=[
  'itemize', 'enumerate'
]

# 箇条書きなど
$latex_figure={
  'figure'=>'[Figure]', 'table'=>'[Table]'
}

# 定理など
$latex_theorem={
  'theorem'=>'Theorem',
  'lemma'=>'Lemma',
  'proposition'=>'Proposition',
  'corollary'=>'Corollary',
  'definition'=>'Definition',
  'acknowledgments'=>'Acknowledgments'
}

# matrix環境など
$latex_matrix={
  'array'=>['', ''],
  'matrix'=>['', ''],
  'pmatrix'=>['(', ')'],
  'vmatrix'=>['|', '|'],
}

# ディスプレイ数学の環境
$latex_env_math_display=[
  'equation', 'equation*', 'eqnarray', 'eqnarray*', 'align', 'align*'
]

# \hugeなどのフォントコマンド
$latex_huge=[
  '\Huge', '\huge', '\LARGE', '\Large', '\large', '\normalsize',
  '\small', '\footnotesize', '\scriptsize', '\tiny',
  '\rmfamily', '\sffamily', '\ttfamily', '\mcfamily', '\gtfamily',
  '\mdseries', '\bfseries',
  '\upshape', '\itshape', '\slshape', '\scshape'
]

################# LaTeX Parser begins...

# 文字列でかつ文字数が１文字以上かの判定
def not_empty_string?(str)
  ret=(str.is_a?(String) && str.length>0)
  ret
end

# コマンドか判定
def is_comment?(x)
  ret=x.is_a?(Array) && x.length>=1 && x[0].is_a?(String) && x[0][0]=='%'
  ret
end

# コマンドか判定
def is_command?(x)
  ret=x.is_a?(Array) && x.length>=1 && x[0].is_a?(String) && x[0].length>=2 && (x[0][0]=='\\' || x[0][0]=='$')
  ret
end

# コマンド名の取得
def get_command(x)
  ret=nil
  if is_command?(x)
    ret=x[0]
  end
  ret
end

# コマンドの引数の取得
def get_command_args(x)
  ret=nil
  if is_command?(x)
    ret=x[1..(x.length-1)]
  end
  ret
end

# ブロックか判定
def is_block?(x)
  ret=x.is_a?(Array) && x.length>=2 && x[0].is_a?(String) && x[0]=='{' && x.last.is_a?(String) && x.last=='}'
  ret
end

# ブロックの中身の取得
def get_block_args(x)
  ret=nil
  if is_block?(x)
    ret=x[1..(x.length-2)]
  end
  ret
end

# オプションブロックか判定
def is_option?(x)
  ret=x.is_a?(Array) && x.length>=2 && x[0].is_a?(String) && x[0]=='[' && x.last.is_a?(String) && x.last==']'
  ret
end

# オプションブロックの中身の取得
def get_option_args(x)
  ret=nil
  if is_option?(x)
    ret=x[1..(x.length-2)]
  end
  ret
end

# \begin{****}か判定
def is_begin?(x)
  ret=x.is_a?(Array) && (x.length==2 || x.length==3) && x[0].is_a?(String) && x[0]=='\begin' && is_block?(x[1]) && x[1].length==3 && x[1][1].is_a?(String)
  ret
end

# \begin{****}の環境名を取得
def get_begin_name(x)
  ret=nil
  if is_begin?(x)
    ret=x[1][1]
  end
  ret
end

# \end{****}か判定
def is_end?(x)
  ret=x.is_a?(Array) && x.length==2 && x[0].is_a?(String) && x[0]=='\end' && is_block?(x[1]) && x[1].length==3 && x[1][1].is_a?(String)
  ret
end

# \end{name}か判定
def is_end_name?(x,name)
  ret=x.is_a?(Array) && x.length==2 && x[0].is_a?(String) && x[0]=='\end' && is_block?(x[1]) && x[1].length==3 && x[1][1].is_a?(String) && x[1][1]==name
  ret
end

# \end{****}の環境名を取得
def get_end_name(x)
  ret=nil
  if is_end?(x)
    ret=x[1][1]
  end
  ret
end

# 環境\begin{****}〜\end{****}か判定
def is_env?(x)
  ret=x.is_a?(Array) && x.length>=2 && is_begin?(x.first) && is_end?(x.last)
  ret
end

# 環境名の取得
def get_env(x)
  ret=nil
  if is_env?(x)
    ret=get_begin_name(x.first)
  end
  ret
end

# 環境の中身の取得
def get_env_args(x)
  ret=nil
  if is_env?(x)
    ret=x[1..(x.length-2)]
  end
  ret
end

# インライン数式$〜$，\(〜\)か判定
def is_math_inline?(x)
  ret=x.is_a?(Array) && x.length>=2 && ((x.first.is_a?(String) && x.first=='$' && x.last.is_a?(String) && x.last=='$') || (is_command?(x.first) && get_command(x.first)=='\(' && is_command?(x.last) && get_command(x.last)=='\)'))
  ret
end

# インライン数式の中身の取得
def get_math_inline_args(x)
  ret=nil
  if is_math_inline?(x)
    ret=x[1..(x.length-2)]
  end
  ret
end

# ディスプレイ数式$〜$，\(〜\)か判定
def is_math_display?(x)
  ret=x.is_a?(Array) && x.length>=2 && ((is_command?(x.first) && get_command(x.first)=='$$' && is_command?(x.last) && get_command(x.last)=='$$') || (is_command?(x.first) && get_command(x.first)=='\[' && is_command?(x.last) && get_command(x.last)=='\]'))
  ret
end

# ディスプレイ数式の中身の取得
def get_math_display_args(x)
  ret=nil
  if is_math_display?(x)
    ret=x[1..(x.length-2)]
  end
  ret
end

# 末尾の改行コードで分割
def latex_parser_lf(src)
  ret=Array.new
  src.each do |a|
    lf=nil
    if /\n$/.match(a)
      lf="\n"
      a.chomp!
    end
    ret.push(a) if not_empty_string?(a)
    ret.push(lf) if lf
  end
  ret.push("\n") if !(/^\n$/=~ret.last)
  ret
end

# コメントで分割
def latex_parser_comment(src)
  ret=Array.new
  src.each do |a|
    if a.is_a?(String)
      if match=/^([^\%]*)(\%)(.*)$/.match(a)
        ret.push(match[1]) if not_empty_string?(match[1])
        ret.push(['%',match[3]])
      else
        ret.push(a)
      end
    else
      ret.push(a)
    end
  end
  ret
end

# 特殊記号のコマンド
$latex_special_cmd=[
  '\\\\', '\{', '\}', '$$', '\[', '\]', '\(', '\)', '\@',
  "\\'e", "\\'a", '\`e', '\`a', '\"e', '\"a',
  '\^', '\=', '\~', '\.', '\,'
]

# 特殊記号のコマンドで分割
def latex_parser_special(src)
  cmd=$latex_special_cmd.map { |x| Regexp.escape(x) }.join('|')
  cmd="^(.*?)(#{cmd})(.*)$"
  regexp=Regexp.new(cmd)
  ret=Array.new
  src.each do |a|
    if a.is_a?(String)
      while match=regexp.match(a)
        if not_empty_string?(match[1])
          ret.push(match[1])
        end
        if not_empty_string?(match[2])
          ret.push([match[2]])
        end
        a=match[3]
      end
      ret.push(a)
    else
      ret.push(a)
    end
  end
  ret
end

# コマンドで分割
def latex_parser_command(src)
  ret=Array.new
  src.each do |a|
    if a.is_a?(String)
      while match=/^([^\\]*)(\\[a-zA-Z\*]+)(.*)$/.match(a)
        ret.push(match[1]) if not_empty_string?(match[1])
        ret.push([match[2]]) if not_empty_string?(match[2])
        a=match[3]
      end
      ret.push(a) if not_empty_string?(a)
    else
      ret.push(a)
    end
  end
  ret
end

# 括弧{}[]_^$で分割
def latex_parser_brackets(src)
  cmd=['{', '}', '[', ']', '$', '_', '^']
  cmd=cmd.map { |x| Regexp.escape(x) }.join('')
  cmd="^(.*?)([#{cmd}])(.*)$"
  regexp=Regexp.new(cmd)
  ret=Array.new
  src.each do |a|
    if a.is_a?(String)
      while match=regexp.match(a)
        ret.push(match[1]) if not_empty_string?(match[1])
        ret.push(match[2]) if not_empty_string?(match[2])
        a=match[3]
      end
      ret.push(a) if not_empty_string?(a)
    else
      ret.push(a)
    end
  end
  ret
end

# 括弧部分を連結する
def latex_parser_combine(src)
  cmd={ '{'=>'}', '['=>']' }
  regexp=cmd.keys.map { |x| Regexp.escape(x) }.join('|')
  regexp="^(#{regexp})$"
  regexp=Regexp.new(regexp)
  l=-1
  b=Array.new
  c=Array.new
  ret=Array.new
  src.each do |a|
    if l<0 && a.is_a?(String) && m=regexp.match(a)
      l=0
      b[l]=cmd[m[1]]
      c[l]=Array.new
      c[l].push(a)
      ret.push(c[l])
    elsif l>=0
      if a.is_a?(String) && m=regexp.match(a)
        l=l+1
        b[l]=cmd[m[1]]
        c[l]=Array.new
        c[l].push(a)
        c[l-1].push(c[l])
      elsif a.is_a?(String) && a==b[l]
        c[l].push(a)
        l=l-1
      else
        c[l].push(a)
      end
    else
      if a.is_a?(Array)
        ret.push(latex_parser_combine(a))
      else
        ret.push(a)
      end
    end
  end
  ret
end

# 特殊括弧部分を連結する
def latex_parser_special_combine(src)
  cmd={ '\('=>'\)', '\['=>'\]' }
  l=-1
  b=Array.new
  c=Array.new
  ret=Array.new
  src.each do |a|
    if l<0 && is_command?(a) && cmd.keys.include?(get_command(a))
      l=0
      b[l]=cmd[get_command(a)]
      c[l]=Array.new
      c[l].push(a)
      ret.push(c[l])
    elsif l>=0
      if is_command?(a) && cmd.keys.include?(get_command(a))
        l=l+1
        b[l]=cmd[get_command(a)]
        c[l]=Array.new
        c[l].push(a)
        c[l-1].push(c[l])
      elsif is_command?(a) && get_command(a)==b[l]
        c[l].push(a)
        l=l-1
      else
        c[l].push(a)
      end
    else
      if a.is_a?(Array)
        ret.push(latex_parser_special_combine(a))
      else
        ret.push(a)
      end
    end
  end
  ret
end


# $,$$の部分を連結する
def latex_parser_dollar(src)
  b=nil
  c=nil
  ret=Array.new
  src.each do |a|
    if c==nil && ((a.is_a?(String) && a=='$') || is_command?(a) && get_command(a)=='$$')
      if a.is_a?(String) && a=='$'
        b='$'
      elsif is_command?(a) && get_command(a)=='$$'
        b='$$'
      end
      c=Array.new
      c.push(a)
      ret.push(c)
    elsif c!=nil
      c.push(a)
      if ((a.is_a?(String) && a==b) || is_command?(a) && get_command(a)==b)
        c=nil
      end
    else
      if a.is_a?(Array)
        ret.push(latex_parser_dollar(a))
      else
        ret.push(a)
      end
    end
  end
  ret
end

# 引数をもつコマンドを連結する
def latex_parser_args(src)
  c=nil
  ret=Array.new
  src.each do |a|
    if c==nil && is_command?(a)
      # コマンドの場合は開始
      c=a
      ret.push(c)
    elsif c!=nil
      # コマンドが開始後にブロックまたはオプションの場合
      if is_block?(a) || is_option?(a)
        c.push(latex_parser_args(a))
      else
        # コマンドが開始後にブロックまたはオプションではない場合
        if !is_command?(a)
          # 次がコマンドではない場合は終了
          c=nil
          ret.push(a)
        else
          # 次もコマンドの場合は開始
          c=a
          ret.push(c)
        end
      end
    elsif a.is_a?(Array)
      # 配列の場合
      ret.push(latex_parser_args(a))
    else
      # 文字列の場合
      ret.push(a)
    end
  end
  ret
end

# 環境を連結する
def latex_parser_env(src)
  l=-1
  b=Array.new
  c=Array.new
  ret=Array.new
  src.each do |a|
    if l<0 && is_begin?(a)
      # \begin{＊}の場合は開始
      l=0
      b[l]=get_begin_name(a)
      c[l]=Array.new
      c[l].push(a)
      ret.push(c[l])
    elsif l>=0
      if is_begin?(a)
        l=l+1
        b[l]=get_begin_name(a)
        c[l]=Array.new
        c[l].push(a)
        c[l-1].push(c[l])
      elsif is_end_name?(a,b[l])
        # \end{＊}の場合は終了
        c[l].push(a)
        l=l-1
      else
        if a.is_a?(Array)
          c[l].push(latex_parser_env(a))
        else
          c[l].push(a)
        end
      end
    elsif a.is_a?(Array)
      ret.push(latex_parser_env(a))
    else
      ret.push(a)
    end
  end
  ret
end

# LaTeXソースコードの構文分割処理
def latex_parser(data)
  # 改行コードで分割処理
  data=latex_parser_lf(data)
  # コメントで分割処理
  data=latex_parser_comment(data)
  # 特殊記号のコマンドで分割処理
  data=latex_parser_special(data)
  # コマンドで分割処理
  data=latex_parser_command(data)
  # 括弧で分割処理
  data=latex_parser_brackets(data)
  # 括弧で連結処理
  data=latex_parser_combine(data)
  # 特殊括弧部分で連結処理
  data=latex_parser_special_combine(data)
  # $,$$で連結処理
  data=latex_parser_dollar(data)
  # コマンドで連結処理
  data=latex_parser_args(data)
  # 環境を連結処理
  data=latex_parser_env(data)
  # 返値
  data
end

# LaTeXの配列データを１つの文字列に変換
def latex_to_string(data)
  str=""
  data.each do |x|
    if x.is_a?(Array)
      str=str+latex_to_string(x)
    else
      str=str+x
    end
  end
  str
end

# LaTeXの配列データをツリー表示
def print_array_tree(data,indent)
  data.each do |x|
    if x.is_a?(String)
      indent.times { print '  ' }
      print '<str>'
      p x
    elsif x.is_a?(Array)
      if is_comment?(x) || is_begin?(x) || is_end?(x) || is_command?(x) || is_block?(x) || is_option?(x)
        indent.times { print '  ' }
        if is_comment?(x)
          print '<cmt>'
        elsif is_begin?(x)
          print '<bgn>'
        elsif is_end?(x)
          print '<end>'
        elsif is_command?(x)
          print '<cmd>'
        end
        p x
      else
        print_array_tree(x,indent+1)
      end
    end
  end
end

################# LaTeX Parser ends.

# LaTeXの配列データを１つの文字列に変換
$label_no=0
$labels=Hash.new
$preamble=Hash.new
$mode_document=false
def latex_to_string(data)
  str=''
  if data.is_a?(String)
    str=data
  elsif data.is_a?(Array)
    data.each do |x|
      if $mode_document==false
        # ヘッダー内の場合
        if x.is_a?(String)
        # 文字列の場合
        elsif x.is_a?(Array)
          # 配列の場合
          if is_command?(x)
            # コマンドの場合
            a=get_command(x)
            b=get_command_args(x)
            if !$preamble.keys.include?(a)
              # コマンドがない場合
              $preamble[a]=Array.new
            end
            $preamble[a].push(b)
            if a=='\newtheorem'
              # \newtheoremコマンドのときは定理環境のリストに追加
              $latex_theorem[b[0][1]]=b[1][1]
            end
          elsif is_env?(x)
            # 環境の場合
            a=get_env(x)
            b=get_env_args(x)
            if a=='document'
              # document環境の場合
              $mode_document=true
              # document環境の中身の表示
              str=str+latex_to_string(b)
            else
              # それ以外の環境の場合
              if $preamble.keys.include?(a)
                # 環境が既にある場合
                $preamble[a].push(b)
              else
                # 環境がない場合
                $preamble[a]=Array.new
                $preamble[a].push(b)
              end
            end
          else
            # それ以外の場合
          end
        else
          # それ以外の場合
        end
      else
        # 文章内の場合
        if x.is_a?(String)
          # 文字列の場合
          if /^ +$/=~x
            # 文字列が空の場合
            if str.length>0
              str=str+x
            end
          elsif x=="\n"
            # 改行コードの場合
            if str.length>0 && !(str[-1]=="\n" && str[-2]=="\n")
              str=str+x
            end
          else
            # 改行コード以外の場合
            # 特殊キャラクタを置換
            y=x
            $latex_special_chars.keys.each do |a|
              y=y.gsub(/#{a}/,$latex_special_chars[a])
            end
            str=latex_to_string_combine_lines(str,y)
          end
        elsif x.is_a?(Array)
          # 配列の場合
          if is_comment?(x)
            # コメントの場合
            str=str+''
          elsif is_block?(x)
            # ブロックの場合
            a=get_block_args(x)
            y=latex_to_string(a)
            y='{'+y.strip+'}'
            str=latex_to_string_combine_lines(str,y)
          elsif is_option?(x)
            # オプションブロックの場合
            a=get_option_args(x)
            y=latex_to_string(a)
            y='['+y.strip+']'
            str=latex_to_string_combine_lines(str,y)
          elsif is_command?(x)
            # コマンドの場合
            # コマンド名と引数の取得
            a=get_command(x)
            b=get_command_args(x)
            if $latex_preamble.include?(a)
              # コマンドがヘッダーに加えるべきものの場合
              if $preamble.keys.include?(a)
                # コマンドが既にある場合
                $preamble[a].push(b)
              else
                # コマンドがない場合
                $preamble[a]=Array.new
                $preamble[a].push(b)
              end
            elsif $latex_maketitle_cmd.include?(a)
              # \maketitleの項目に含まれる場合
              if $preamble.keys.include?(a)
                $preamble[a].push(b)
              else
                $preamble[a]=Array.new
                $preamble[a].push(b)
              end
            elsif a=='\today'
              # 今日の日付
              str=latex_to_string_combine_lines(str,Date.today.to_s)
            elsif a=='\maketitle'
              # タイトルの表示
              str=str+latex_to_string_maketitle(str)
            elsif $latex_par.include?(a)
              # 段落替え
              str=latex_to_string_par(str)
            elsif a=='\\\\'
              # 強制改行
              #str=str+a
            elsif $latex_text.include?(a)
              # \text{＊}などの場合
              y=latex_to_string_array_join(b,', ','','')
              str=latex_to_string_combine_lines(str,y)
            elsif a=='\label'
              # \label{＊}の場合
              c=b[0]
              if !$labels.keys.include?(c)
                $label_no=$label_no+1
                $labels[c]="#{$label_no}"
              end
            str=latex_to_string_combine_lines(str,"[#{$labels[c]}]")
            elsif a=='\ref'
              # \ref{＊}の場合
              c=b[0]
              if !$labels.keys.include?(c)
                $label_no=$label_no+1
                $labels[c]="#{$label_no}"
              end
              str=latex_to_string_combine_lines(str,$labels[c])
            elsif a=='\eqref'
              # \eqref{＊}の場合
              c=b[0]
              if !$labels.keys.include?(c)
                $label_no=$label_no+1
                $labels[c]="#{$label_no}"
              end
              str=latex_to_string_combine_lines(str,"(#{$labels[c]})")
            elsif a=='\bibitem'
              # \bibitem{＊}の場合
              y=latex_to_string_array_join(b,', ','','')
              str=latex_to_string_combine_lines(str,"[#{y}]")
            elsif a=='\cite'
              # \cite{＊}の場合
              y=latex_to_string_array_join(b,', ','','')
              str=latex_to_string_combine_lines(str,"[#{y}]")
            elsif a=='\frac'
              # \frac{＊}{＊}の場合
              y=latex_to_string_array_join(b,'/','(',')')
              str=latex_to_string_combine_lines(str,y)
            elsif $latex_command.keys.include?(a)
              # コマンドのリストにあれば出力
              str=latex_to_string_combine_lines(str,$latex_command[a])
            elsif $latex_section.keys.include?(a)
              # 節などの場合
              str=latex_to_string_par(str)
              z=latex_to_string_array_join(b,' / ','','')
              str=str+$latex_section[a]+' '+z+"\n\n"
            elsif $latex_caption.keys.include?(a)
              # キャプションなどの場合
              if str[-1]!="\n"
                str=str+"\n"
              end
              z=latex_to_string_array_join(b,', ','','')
              str=str+$latex_caption[a]+' '+z
            elsif $latex_huge.include?(a)
              # \hugeなどのフォントコマンド
              str=str+''
            else
              # それ以外のコマンドの場合
              str=str+latex_to_string(x)
            end
          elsif is_math_inline?(x)
            # インライン数式の場合
            a=get_math_inline_args(x)
            y=latex_to_string(a)
            y=y.strip
            y=y.gsub(/\s+/,'')
            y='$'+y+'$'
            str=latex_to_string_combine_lines(str,y)
          elsif is_math_display?(x)
            # ディスプレイ数式の場合
            a=get_math_display_args(x)
            str=latex_to_string_combine_lines(str,'$$')
            str=str+"\n"
            y=latex_to_string_math_display(a)
            str=str+y
            str=str+"\n" if str[-1]!="\n"
            str=str+'$$'
          elsif is_env?(x)
            # 環境の場合
            # 環境名の取得
            a=get_env(x)
            b=get_env_args(x)
            if $latex_maketitle_env.include?(a)
              # \maketitleの項目に含まれる場合
              if $preamble.keys.include?(a)
                $preamble[a].push(b)
              else
                $preamble[a]=Array.new
                $preamble[a].push(b)
              end
            elsif $latex_bibitem.keys.include?(a)
              # thebibliography環境の場合
              str=latex_to_string_par(str)
              str=str+$latex_bibitem[a]
              str=latex_to_string_par(str)
              str=str+latex_to_string_bibliography(b)
            elsif $latex_item.include?(a)
              # 箇条書き環境の場合
              str=str+"\n" if str[-1]!="\n"
              str=str+latex_to_string_itemize(b)
            elsif $latex_env_math_display.include?(a)
              # ディスプレイ数学の環境の場合
              str=latex_to_string_combine_lines(str,'$$')
              str=str+"\n"
              y=latex_to_string_math_display(b)
              str=str+y
              str=str+"\n" if str[-1]!="\n"
              str=str+'$$'
            elsif $latex_matrix.keys.include?(a)
              # matrixfigure環境などの場合
              str=str+"\n" if str[-1]!="\n"
              y=latex_to_string_matrix(b,$latex_matrix[a][0],$latex_matrix[a][1])
              str=str+y
            elsif $latex_figure.include?(a)
              # figure環境などの場合
              str=str+"\n" if str[-1]!="\n"
              str=str+$latex_figure[a]+"\n"
              y=latex_to_string(b)
              y=y.lstrip
              str=str+y
            elsif $latex_theorem.keys.include?(a)
              # 定理環境などの場合
              str=latex_to_string_par(str)
              str=str+$latex_theorem[a]+'. '
              str=str+latex_to_string(b)
            else
              # それ以外の環境の場合
#              str=str+latex_to_string(x)
              str=str+latex_to_string(b)
            end
          else
            # それ以外の配列の場合
            str=str+latex_to_string(x)
          end
        end
      end
    end
  end
  str
end

# 段落替え
def latex_to_string_par(str)
  ret=str
  if ret.length>0 && !(/^\s+$/=~ret)
    if ret[-2]=="\n" && ret[-1]=="\n"
    elsif ret[-2]!="\n" && ret[-1]=="\n"
      ret=ret+"\n"
    elsif ret[-2]!="\n" && ret[-1]!="\n"
      ret=ret+"\n\n"
    end
  end
  ret
end

# 最後の改行の個数をカウントして連結
def latex_to_string_combine_lines(str,x)
  if str==''
    ret=x.lstrip
  elsif str[-2]=="\n" && str[-1]=="\n"
    ret=str+x.lstrip
  elsif str[-1]==' ' || str[-1]=="\n" || x[0]==" " || x[0]=="\n"
    ret=str.rstrip+' '+x.lstrip
  else
    ret=str.rstrip+x.lstrip
  end
  ret
end

# matrix環境など
def latex_to_string_matrix(data,left,right)
  ret=Array.new
  if data.is_a?(Array)
    c=Array.new
    ret.push(c)
    c.push('{')
    data.each do |x|
      if x.is_a?(String)
        if !(/^\s*$/=~x)
          y=x.strip
          c.push(y)
        end
      elsif is_command?(x) && get_command(x)=='\\\\'
        c.push('}')
        c=Array.new
        ret.push(c)
        c.push('{')
      else
        c.push(x)
      end
    end
    if c[-1]!='}'
      c.push('}')
    end
  end
  ret=latex_to_string_array_join(ret,"\n",left,right)
end


# ディスプレイ数式環境を変換
def latex_to_string_math_display(data)
  ret=Array.new
  if data.is_a?(Array)
    c=Array.new
    ret.push(c)
    c.push('{')
    data.each do |x|
      if x.is_a?(String)
        if !(/^\s*$/=~x)
          y=x.strip
          c.push(y)
        end
      elsif is_command?(x) && get_command(x)=='\\\\'
        c.push('}')
        c=Array.new
        ret.push(c)
        c.push('{')
      else
        c.push(x)
      end
    end
    if c[-1]!='}'
      c.push('}')
    end
  end
  ret=latex_to_string_array_join(ret,"\n",'','')
end

# bibliography環境を変換
def latex_to_string_bibliography(data)
  ret=Array.new
  if data.is_a?(Array)
    c=nil
    data.each do |x|
      if is_command?(x)
        a=get_command(x)
        if a=='\bibitem'
          if c!=nil
            c.push('}')
          end
          c=Array.new
          ret.push(c)
          c.push('{')
          c.push(x)
        end
      elsif c!=nil
        c.push(x)
      end
    end
    if c!=nil
      c.push('}')
    end
  end
  ret=latex_to_string_array_join(ret,"\n\n",'','')
end

# 箇条書き環境を変換
def latex_to_string_itemize(data)
  ret=Array.new
  if data.is_a?(Array)
    c=nil
    data.each do |x|
      if is_command?(x)
        a=get_command(x)
        if a=='\item'
          if c!=nil
            c.push('}')
          end
          c=Array.new
          ret.push(c)
          c.push('{')
          c.push(x)
        end
      elsif c!=nil
        c.push(x)
      end
    end
    if c!=nil
      c.push('}')
    end
  end
  ret=latex_to_string_array_join(ret,"\n",'','')
end

# 配列を連結して変換
def latex_to_string_array_join(x,sep,left,right)
  ret=''
  if x.is_a?(String)
    if ret==''
      ret=x
    else
      ret=ret+sep+x
    end
  else x.is_a?(Array)
    x.each do |a|
      b=latex_to_string(a)
      if is_block?(a)
        b=b.gsub(/^\s*\{\s*/,'').gsub(/\s*\}\s*$/,'')
      elsif is_option?(a)
        b=b.gsub(/^\s*\[\s*/,'').gsub(/\s*\]\s*$/,'')
      end
      b=left+b+right
      if ret==''
        ret=b
      else
        ret=ret+sep+b
      end
    end
  end
  ret
end

# \maketitleでタイトルの表示
def latex_to_string_maketitle(str)
  $latex_maketitle_cmd.keys.each do |x|
    if $preamble.keys.include?(x)
      $preamble[x].each do |y|
        z=latex_to_string_array_join(y,' / ','','')
        str=str+$latex_maketitle_cmd[x]+' '+z+"\n\n"
      end
    end
  end
  $latex_maketitle_env.keys.each do |x|
    if $preamble.keys.include?(x)
      $preamble[x].each do |y|
        z=latex_to_string(y).strip
        str=str+$latex_maketitle_env[x]+' '+z+"\n\n"
      end
    end
  end
  str
end

##################################

# options
while arg=ARGV.shift
  if /^-v$/=~arg
    verbose=1
  elsif /^-vv$/=~arg
    verbose=2
  elsif /^-i$/=~arg
    input='file'
    input_fname=ARGV.shift
  elsif /^-o$/=~arg
    output='file'
    output_fname=ARGV.shift
  elsif /^stdin$/=~input
    input='file'
    input_fname=arg
  elsif /^file$/=~input && /^stdout$/=~output
    output='file'
    output_fname=arg
  end
end

if verbose>0
  puts "verbose=#{verbose}"
  puts "input=#{input}"
  puts "input_fname=#{input_fname}"
  puts "output=#{output}"
  puts "output_fname=#{output_fname}"
end

# ファイルを読み込み行ごとの配列として格納
if /^stdin$/=~input
  lines=STDIN.readlines
else
  begin
    fid=File.open(input_fname,mode='rt')
    lines=fid.readlines
  rescue
    puts "Error: faild to open: #{input_fname}"
    exit
  end
end

# 行ごとの配列からLaTeXのデータに変換
data=latex_parser(lines)

# LaTeXの配列データをそのまま表示
if verbose>=2
  print_array_tree(data,0)
end

# １つの文字列に変換
str=latex_to_string(data)

# 出力
if /^stdout$/=~output
  STDOUT.print str
else
  begin
    fid=File.open(output_fname,mode='wt')
    fid.print str
  rescue
    puts "Error: faild to write: #{output_fname}"
    exit
  end
end

#EOF
```