HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Repetitive replacement for expressing fractions in LaTeX

Submitted by: @import:stackexchange-codereview··
0
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 / 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 %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]
end


Here, 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) )
end


The 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]
end
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) )
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.