How can I replace LaTeX $...$ and $$...$$ notations by something like <div>$...$</div>?

python, regex

Solution

We can accomplish this by doing two steps replacement:

import re
str = "$rac{some}{latex}$$$\int^e_v {en} more$$\$rac{some}{latex}$$$\int^e_v {en} more$$\n$rac{some}{latex}$\n$$\int^e_v {en} more$$\n\$rac{some}{latex}$\n$$\int^e_v {en} more$$"

#first step:
str = re.sub(r'(?<![\\])\$\$([^\$]+)\$\$', "<div>$$\g<1>$$</div>", str)
#second step:
str = re.sub(r'(?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)', "<span>$\g<1>$</span>", str)
print str

Explanation:

First step:

We perform a replace only in the `$$` occurrences, replacing it by `<div>$$\g<1>$$</div>`(`\g<1>` will be replaced by the first group defined in the regex).

str = re.sub(r'(?<![\\])\$\$([^\$]+)\$\$', "<div>$$\g<1>$$</div>", str)

Realize that we are using this regex `(?<![\\])\$\$([^\$]+)\$\$` regex101 example which works in the following way:

- `(?<![\\]) ...` Defines that we are matching something `...` which is not preceded by a `\` [in the regex: `(?<![\\])`]. So firstly we said we do not want a `\` before the expression.

- `... \$\$ ...` Defines that we have to have a `$$` occurrence in the beginning of the string.

- `... ([^\$]+)` Defines that we want everything but a `$` after the previous step [in the regex `[^\$]+`]. And then we put it into a capture group `(...)`, for after refer to it in the code.

- `... \$\$` After all we finish the expression saying that we have to have a `$$` occurrence in the final of the string.

Second step:

We perform a replace only in the `$` occurrences, replacing it by `<span>$\g<1>$</span>`(again, the `\g<1>` will be replaced by the first group match defined in the regex)

str = re.sub(r'(?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)', "<span>$\g<1>$</span>", str)

Realize also that we are using this other regex `(?<![\$\\])\$([^\$]+)(?:(?<!\<div\>)(?<!\\)\$)` (yeah, little bit harder) regex101 example which works in the following way:

- `(?<![\$\\]) ...` Defines that we are matching something `...` which is not preceded by a `\` or a `$` [in the regex: `(?<![\\\$])`]. So firstly we said we do not want a `\` or a `$` in the beginning.

- `... \$ ...` Defines that our string needs to start with one `$`

- `... ([^\$]+) ...` Defines a capture group with everything but `$`, for future call back.

- `... (?:(?<!\<div\>)(?<!\\)\$)` We finish saying that our string finish with a `$` but not preceded by a div [in the regex: `?<!\<div\>)`] or a `\` [in the regex: `(?<!\\)`]. (then we put it all into a non-capture group to say that all of this is only one thing `(?:(?<!\<div\>)(?<!\\)\$)`)

Note: perhaps there are more efficient ways to get this result.

Problem

I currently have the problem that Jekyll does not work well with Markdown and LaTeX. So I have a lot of articles with `$\frac{some}{latex}$` or `$$\int^e_v {en} more$$`. How can I replace `$...$` by `<span>$...$</span>` and `$$...$$` by `<div>$$..$$</div>`? Things that make this task difficult are: - The `...` might include newlines. In fact, `...` might contain anything, except `$` - The first `$` gets replaced by `<span>$`, but the second one by `$</span>` - `$...$` and `$$...$$` can be used in the same document (but always seperated by at least one whitespace) edit: I've just seen that I also need some escaping. So the task has one more difficulty: - `\$` should not be matched for any of the two cases above.

Original source