patternMinor
Repetitive replacement for expressing fractions in LaTeX
Viewed 0 times
expressinglatexrepetitiveforfractionsreplacement
Problem
I am converting natural math expressions with fractions to Latex code.
What I have done seems to work on examples I've tested, but I'm not sure if the algorithm is safe. And maybe the string part could be improved.
Maybe a better approach could be replace the
I don't know how to make that.
Some examples
My try :
```
function ToFrac (s)
while s:find ("/") ~= nil
do
-- Remplace : \dfrac{}{}/() -> \dfrac{\dfrac...}{}
if ( s:find ( '\\dfrac%b{}%b{}/%b()' , j ) ~= nil )
then
x,y,num,den = s:find( '(\\dfrac%b{}%b{})/(%b())' )
den = den:gsub( '.(.+).' , '%1' )
s = s:gsub( '(\\dfrac%b{}%b{})/(%b())',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
-- Remplace : ()/\dfrac{}{} -> \dfrac{()}{\dfrac...}
if ( s:find ( '(%b()/\\dfrac%b{}%b{}' ) ~= nil )
then
x,y,num,den = s:find( '((%b())/(\\dfrac%b{}%b{})' )
num = num:gsub( '.(.+).' , '%1' )
s = s:gsub( '((%b())/()\\dfrac%b{}%b{})',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
-- Remplace : ()/() -> \dfrac{}{}
if ( s:find ( '%b()/%b()' , 1 ) ~= nil )
then
x,y,num,den = s:find( '(%b())/(%b())' )
num = num:gsub( '.(.+).' , '%1' )
den = den:gsub( '.(.+).' , '%1' )
s = s:gsub( '(%b())/(%b())',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
end -- while
return (s)
end
s = "((a)/(b))/(c)"
print (s, ToFrac(s))
s = "(a)/((b)/(c))"
print (s, ToFrac(s))
s =
What I have done seems to work on examples I've tested, but I'm not sure if the algorithm is safe. And maybe the string part could be improved.
Maybe a better approach could be replace the
/ from left to right, but how in my case target the next?- By a generic pattern that matches the 3 cases at once.
- By selecting specific
/and passing tests on it and remplacing it after.
I don't know how to make that.
Some examples
((a)/(b))/(c) -> \dfrac{\dfrac{a}{b}}{c}
(a)/((b)/(c)) -> \dfrac{a}{\dfrac{b}{c}}
(a)/(b)/(c)/(d) -> \dfrac{\dfrac{\dfrac{a}{b}}{c}}{d}
((a)/(b))/((c)/(d)) -> \dfrac{\dfrac{a}{b}}{\dfrac{c}{d}}My try :
```
function ToFrac (s)
while s:find ("/") ~= nil
do
-- Remplace : \dfrac{}{}/() -> \dfrac{\dfrac...}{}
if ( s:find ( '\\dfrac%b{}%b{}/%b()' , j ) ~= nil )
then
x,y,num,den = s:find( '(\\dfrac%b{}%b{})/(%b())' )
den = den:gsub( '.(.+).' , '%1' )
s = s:gsub( '(\\dfrac%b{}%b{})/(%b())',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
-- Remplace : ()/\dfrac{}{} -> \dfrac{()}{\dfrac...}
if ( s:find ( '(%b()/\\dfrac%b{}%b{}' ) ~= nil )
then
x,y,num,den = s:find( '((%b())/(\\dfrac%b{}%b{})' )
num = num:gsub( '.(.+).' , '%1' )
s = s:gsub( '((%b())/()\\dfrac%b{}%b{})',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
-- Remplace : ()/() -> \dfrac{}{}
if ( s:find ( '%b()/%b()' , 1 ) ~= nil )
then
x,y,num,den = s:find( '(%b())/(%b())' )
num = num:gsub( '.(.+).' , '%1' )
den = den:gsub( '.(.+).' , '%1' )
s = s:gsub( '(%b())/(%b())',
"\\dfrac{"..num.."}{"..den.."}" , 1 )
end
print ('### -- ', s)
end -- while
return (s)
end
s = "((a)/(b))/(c)"
print (s, ToFrac(s))
s = "(a)/((b)/(c))"
print (s, ToFrac(s))
s =
Solution
You can use a recursive function with the pattern
Here, I'm storing the operands as nodes in a stack. I tested the above function for the inputs:
The final results were:
%b() as follows:function ToFrac( sInput )
local tStack = {}
for sOperand in sInput:gmatch "%b()" do
table.insert( tStack, sOperand:sub(2, -2) )
end
while true do
if #tStack <= 1 then break end
local sNumerator = table.remove( tStack, 1 )
if sNumerator:find '/' then sNumerator = ToFrac( sNumerator ) end
local sDenominator = table.remove( tStack, 1 )
if sDenominator:find '/' then sDenominator = ToFrac( sDenominator ) end
table.insert( tStack, 1, ([[\dfrac{%s}{%s}]]):format(sNumerator, sDenominator) )
end
return tStack[1]
endHere, I'm storing the operands as nodes in a stack. I tested the above function for the inputs:
local s = {
"((a)/(b))/(c)",
"(a)/((b)/(c))",
"(a)/((b)/(c))/(d)",
"(a)/(b)/(c)/(d)",
"((a)/(b))/((c)/(d))",
}
for k, v in pairs(s) do
print( v, ToFrac(v) )
endThe final results were:
((a)/(b))/(c) \dfrac{\dfrac{a}{b}}{c}
(a)/((b)/(c)) \dfrac{a}{\dfrac{b}{c}}
(a)/((b)/(c))/(d) \dfrac{\dfrac{a}{\dfrac{b}{c}}}{d}
(a)/(b)/(c)/(d) \dfrac{\dfrac{\dfrac{a}{b}}{c}}{d}
((a)/(b))/((c)/(d)) \dfrac{\dfrac{a}{b}}{\dfrac{c}{d}}Code Snippets
function ToFrac( sInput )
local tStack = {}
for sOperand in sInput:gmatch "%b()" do
table.insert( tStack, sOperand:sub(2, -2) )
end
while true do
if #tStack <= 1 then break end
local sNumerator = table.remove( tStack, 1 )
if sNumerator:find '/' then sNumerator = ToFrac( sNumerator ) end
local sDenominator = table.remove( tStack, 1 )
if sDenominator:find '/' then sDenominator = ToFrac( sDenominator ) end
table.insert( tStack, 1, ([[\dfrac{%s}{%s}]]):format(sNumerator, sDenominator) )
end
return tStack[1]
endlocal s = {
"((a)/(b))/(c)",
"(a)/((b)/(c))",
"(a)/((b)/(c))/(d)",
"(a)/(b)/(c)/(d)",
"((a)/(b))/((c)/(d))",
}
for k, v in pairs(s) do
print( v, ToFrac(v) )
end((a)/(b))/(c) \dfrac{\dfrac{a}{b}}{c}
(a)/((b)/(c)) \dfrac{a}{\dfrac{b}{c}}
(a)/((b)/(c))/(d) \dfrac{\dfrac{a}{\dfrac{b}{c}}}{d}
(a)/(b)/(c)/(d) \dfrac{\dfrac{\dfrac{a}{b}}{c}}{d}
((a)/(b))/((c)/(d)) \dfrac{\dfrac{a}{b}}{\dfrac{c}{d}}Context
StackExchange Code Review Q#97508, answer score: 3
Revisions (0)
No revisions yet.