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