0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

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

しかし,全ての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...

# 文字列でかつ文字数が1文字以上かの判定
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の配列データを1つの文字列に変換
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の配列データを1つの文字列に変換
$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

# 1つの文字列に変換
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
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?