6

I have a source file that was originally coded in TeX (well, this is actually a conTeXt file). A fraction like 1/(2/x^2) is coded as {1 \over {2 \over x^2}}. I'd like to convert to LaTeX syntax, that is \frac{1}{\frac{2}{x^2}}.

Any hints? Thanks.

cjorssen
  • 197
  • 6
  • How many instances are there in the file? Are you looking for a fully automated search-and-replace? Searching for instances of `\over` and replacing them manually is the easiest way. Coming up with a regexp to match these things and replace them automatically may be very hard. – NickD Mar 15 '19 at 12:11
  • @NickD Well, hundreds of them... – cjorssen Mar 15 '19 at 12:16
  • Your nice limitation of `\over` arguments can be handled quite simply. But, note that there are more constructs that limit the arguments of `\over` like `$ a \over b $ $ c \over d $` or `$\matrix{ a \over b & c \over d }$`. In each of those cases `a \over b` and `c \over d` are rendered as separate fractions. That makes your quest really hard. If I would try a solution could I assume that `\over` arguments are always delimited by braces? It would lead to a seriously defective LaTeX document if one takes that assumption and the TeX source does not satisfy it. – Tobias Mar 15 '19 at 16:15
  • Note also that the general solution to this problem would mean the implementation of a TeX interpreter since with TeX everything is possible. For an instance after changing all catcodes a TeX document does not look like a TeX document anymore. Some assumptions about the TeX document at hand are required for solving this problem with limited resources. – Tobias Mar 15 '19 at 16:45
  • @Tobias Yes, you can assume that each argument is delimited by braces. Thanks for your interest in my question. – cjorssen Mar 15 '19 at 21:04

3 Answers3

5

The command my-replace-over-with-frac defined in the following Elisp code assumes that \over arguments are always delimited by braces.

There are more constructs that limit the arguments of \over like $ a \over b $ $ c \over d $ or $\matrix{ a \over b & c \over d }$. In each of those cases a \over b and c \over d are rendered as separate fractions.

If one ignores that it may lead to an invalid LaTeX document. For that reason the default application of my-replace-over-with-frac is interactive by default. For each match of \over you are asked whether you want to accept the replacement or not. The text modifications are marked with yellow color.

If you skip some replacements you can afterwards search for \over to find those cases and edit them.

If you are venturesome you can call my-replace-over-with-frac with prefix-arg. In that case all replacements are done without user-interaction.

(defun my-next-over (&rest args)
  "Search for the next \\over in a math environment.
ARGS are the arguments starting at the 2nd one of `search-forward'."
  (cl-loop while (apply #'search-forward "\\over" args)
       when (and (save-match-data (texmathp))
             (null (nth 8 (syntax-ppss (point)))))
       return (point)
       finally return nil))

(defun my-replace-over-with-frac (&optional b e force)
  "Replace {a \\over b} with {\frac{a}{b}} in region from B to E.
Make replacements without questions if FORCE is non-nil.
Thereby, a and b can be terms that can contain fractions themselves."
  (interactive (append
        (if (use-region-p)
            (list (region-beginning) (region-end))
          (list nil nil))
        (list prefix-arg)))
  (save-point
   (unless b (setq b (point-min)))
   (unless e (setq e (point-max)))
   (goto-char b)
   (let ((ol-over (make-overlay 1 1))
     (ol-frac (make-overlay 1 1))
     (ol-brace (make-overlay 1 1)))
     (unwind-protect
     (progn
       (overlay-put ol-over 'face 'match)
       (overlay-put ol-frac 'face 'match)
       (while (my-next-over e t)
         (move-overlay ol-over (match-beginning 0) (match-end 0))
         (replace-match "}{")
         (goto-char (match-beginning 0))
         (backward-up-list)
         (let ((b-frac (point)))
           (insert "{\\frac")
           (move-overlay ol-frac b-frac (point)))
         (forward-sexp 2)
         (insert "}")
         (move-overlay ol-brace (1- (point)) (point))
         (if (or force
             (y-or-n-p "Apply? "))
         (goto-char (overlay-end ol-over)) ;; consider other occurences of \over in the second operand
           (delete-region (overlay-start ol-over) (overlay-end ol-over))
           (goto-char (overlay-start ol-over))
           (insert "\\over")
           (save-point
        (delete-region (overlay-start ol-frac) (overlay-end ol-frac))
        (delete-region (overlay-start ol-brace) (overlay-end ol-brace))))
         )
       )
       (delete-overlay ol-over)
       (delete-overlay ol-frac)
       (delete-overlay ol-brace)))))

           (delete-overlay ol-frac)))))

The interaction stuff hides a bit the simplicity of the method.

The structure of the method is:

(while (search-forward "\\over")
  (save-point
    (replace-match "}{")
    (backward-up-list)
    (insert "\\frac")))
Tobias
  • 32,569
  • 1
  • 34
  • 75
1

The following code replaces {1 \over {2 \over x^2}} with \frac{1}{\frac{2}{x^2}}.

(save-excursion
  (goto-char (point-min))
  (while (re-search-forward
          "{\\([0-9]*\\)\s\\\\over\s{\\([0-9]*\\)\s\\\\over\s\\([^}]*\\)}}" nil t)
    (replace-match "\\\\frac{\\1}{\\\\frac{\\2}{\\3}}")))
jagrg
  • 3,824
  • 4
  • 19
  • Just imagine what it will look like for arbitrary, nested occurrences of `\over`, if it's even possible... – NickD Mar 15 '19 at 15:26
  • Thanks for taking the time to answer (+1). This works with the sample case I provided in my question. However, Tobias answer fits more to my needs since it is more general. – cjorssen Mar 17 '19 at 13:45
0

I believe you may be looking for the function replace-string, or replace-regexp. These let you enter a before (frac) and after (over) and replaces found occurrences.
Here is documentation: https://www.gnu.org/software/emacs/manual/html_node/emacs/Regexp-Replace.html

If you want to go one by one to make sure that what you're changing should be changed (perhaps an instance where you want to change some, but not all), you want query-replace-regexp.
Here is documentation for that: https://www.gnu.org/software/emacs/manual/html_node/emacs/Query-Replace.html

DerpKat
  • 56
  • 5
  • Thanks for taking the time to answer. However, what I'm looking for is a bit more complex since `\over` and `\frac` both take two "arguments" but the syntax is different: `{arg 1 \over arg2}` and `\frac{arg1}{arg2}`. Plus I need a way to deal with recursive call. I guess the way to go is `regexp` but, as a beginner, I need some extra help. – cjorssen Mar 15 '19 at 12:13