OVH Cloud OVH Cloud

macro big pour latex

14 réponses
Avatar
Ph. Idlavi
Bonjour,

Une région contient, par exemple, le texte suivant :
((des commandes (des commandes (des commandes (des commandes )des
commandes )des commandes )des commandes) des commandes)

je voudrais la convertir en :
\Bigg(\bigg(des commandes \Big(des commandes \big(des commandes (des
commandes )des commandes \big)des commandes \Big)des commandes\bigg) des
commandes\Bigg)

Quelqu'un pourrait-il m'indiquer un début de code pour effectuer la
conversion ?
Je ne vois même pas par où commencer...

Merci de votre aide.
--
Philippe.

4 réponses

1 2
Avatar
Ph. Idlavi
"drkm" écrivit le 08/12/05 à 16h52:13 :

Ph. Idlavi wrote:

Bonjour

Je crosse-poste sur f.c.algorithmes (depuis f.c.a.emacs), me rendant
compte après avoir rédigé mon article que ce dernier y avait
peut-être plus sa place. Je ne l'ai pas retouché, je pense que le
problème est clair pour quelqu'un qui débarque dans la discussion.
Juste un détail : il est à un moment question d'une liste de strings
; la voici : "Bigg", "bigg", "Big", "big".

* un M-x mm-replace sur :
(a+(a+b)+(c+d)+e)+((a+b)+c)
donne :
Bigg(a+bigg(a+bbigg)+bigg(c+dbigg)+eBigg)+((a+b)+c)



alors qu'il faudrait obtenir "simplement":
big(a+(a+b)+(c+d)+ebig)+big((a+b)+cbig)



Mmh. J'ai sans doute mal compris l'énoncé, alors. Je pensais
qu'il fallait partir de "Bigg" vers "big", en employant le premier au
premier niveau de parenthèses, le second au second niveau, etc. S'il
y avait trop de niveaux et que l'on avait épuisé la liste, on
ignorait les parenthèses.

Il semblerait plutôt qu'il faille partir du niveau le plus profond,
le laisser tel quel, puis parcourir la liste des macros dans l'autre
sens en remontant de niveau de profondeur. Donc :

() -> ()
(()) -> big(()big)
((())) -> Big(big(()big)Big)
(((()))) -> bigg(Big(big(()big)Big)bigg)
(()(())) -> Big(big(big)big(()big)Big)


Est-ce bien cela ? Notamment le dernier exemple. Si oui, ça
complique un peu les choses, mais il devrait y avoir moyen d'adapter
assez facilement le 'mm-replace' que je t'ai proposé.



C'est bien cela...
Je n'ai pas essayé d'adapter ce que tu as proposé.


Il faut garder la position des parenthèses du niveau courant. La
fonction retourne le niveau courant (0 = le plus profond). Lorsque
l'on est au niveau 0, on retourne 0. Sinon, on retourne le niveau
maximum des appels récursifs (donc des niveaux inférieurs) + 1.

Le problème, c'est que le niveau d'un sous-ensemble peut dépendre
d'un sous-ensemble disjoint. Dans le dernier exemple ci-dessus, le
premier '()' est au niveau 1. Mais on ne peut le savoir qu'après
avoir rencontré le second '()', qui lui est au niveau 0.

Mmh. En fait, je ne vois pas d'autre moyen que de procéder en deux
phases. La première dresse la carte des parenthèses, la seconde la
parcours par niveau et effectue les changements ad hoc.

Quelqu'un voit-il une autre solution ?



un bout de code approchant le résultat escompté mais il
reste quelques problèmes :

8<------8<------8<------8<------8<------8<------8<------8<------8<------
(defun paren-depth-at-point (begin)
;;Retourne la profondeur du point dans les parenthèses
(save-excursion
(let ((thedepth 0) (notbegin t))
(while (and (>= (point) begin) notbegin);;Problème avec le début
;;du buffer
(if (eq ?( (char-after (point)))
(incf thedepth)
(if (eq ?) (char-before))
(decf thedepth)))
(if (not (bobp)) (backward-char 1) (setq notbegin nil))
)
thedepth)))

(defun paren-max-depth-region (beginr endr)
;;Retourne le profondeur maximale des parenthèses de la région
(interactive "r")
(save-excursion
(let ((max-depth 0) (curr-depth 0))
(goto-char beginr)
(while (and (< (point) endr) (re-search-forward "(" nil t 1))
(setq curr-depth (paren-depth-at-point beginr))
(if (> curr-depth max-depth)
(setq max-depth curr-depth)))
max-depth)))


(defvar mm-big-liste '("" "big" "Big" "bigg" "Bigg"))

(defun big-paren-region (beginr endr)
;;Converti la région avec les big
(interactive "r")
(save-excursion
(let ((list mm-big-liste) (maxdepth 0) (curdepth 0))
(narrow-to-region beginr endr)
(goto-char beginr)
(when (re-search-forward "(*)" nil t 1)
(setq maxdepth (paren-max-depth-region beginr endr));;Prof max
(if (<= maxdepth 5)
(progn
(goto-char beginr)
(while (re-search-forward "(" nil t 1)
(backward-char 1)
(setq curdepth (paren-depth-at-point beginr));;Prof courante
(insert (nth (- maxdepth curdepth) list))
(match-paren 1)
(insert (nth (- maxdepth curdepth) list))
(match-paren 1)
(forward-char 1)
))
(message "Profondeur maximale dépassée..."))
(widen);;En cas de pb C-x n w
))))
8<------8<------8<------8<------8<------8<------8<------8<------8<------

Usage :
* sélectionner une région contenant des parenthèses (sans erreur de
fermeture)
* M-x big-paren-region

Par exemple :
(a*(a+b)+(c+d*(a+b))*e)((a+b)+c)

donne :
Big(a*big(a+bbig)+big(c+d*(a+b)big)*eBig)big(big(a+bbig)+cbig)

(a(a)a(a(a)a)a) donne : Big(abig(abig)abig(a(a)abig)aBig)
(ton dernier exemple mais il y a un problème si toutes les parenthèses
se touchent.)


Par contre :
(a*(b+c*(a+b*(b+c))))+a*(b+c*(b+c))

donne :
bigg(a*Big(b+c*big(a+b*(b+c)big)Big)bigg)+a*bigg(b+c*Big(b+cBig)bigg)

alors qu'il faudrait :
bigg(a*Big(b+c*big(a+b*(b+c)big)Big)bigg)+a*big(b+c*(b+c)big)

Il faut encore que je fignoler le code (manque de temps) mais je pense
que l'idée y est...

--
Philippe.
Avatar
drkm
Ph. Idlavi wrote:

Il faut encore que je fignoler le code (manque de temps) mais je pense
que l'idée y est...



Je n'en ai pas trop non plus pour l'instant. J'essaierai de penser
à y jeter un oeil demain (ou peut-être ce soir, si j'en ai assez vite
marre de ce que je suis en train de faire :-p).

--drkm
Avatar
Ph. Idlavi
Bonjour,

J'ai trouvé un algorithme assez simple qui réalise la tache demandée.
Pour simplifier, je dispose des fonctions suivantes :

paren-depth-at-point (begin) : retourne la profondeur de
parenthèses où se trouve le point en partant de begin.
(*) -> 0 ((*))->1....

paren-max-depth-region (beginr endr) :
retourne le profondeur maximale des parenthèses de la région comprise
entre beginr et endr.

match-paren-point () : retourne le point de la parenthèse correspondante

mm-big-liste contient la liste de chaine à insérer ("" "big" "Big"
"bigg" "Bigg")

8<------8<------8<------8<------8<------8<------8<------8<------8<------
L'algorithme est alors le suivant :
* En entrée : une région avec des parenthèses bien formées.
* Se placer au début de la région à modifier ;
* Pour chaque parenthèse ouvrante :
^ * Calculer "depth" : profondeur maxi de la région comprise entre
| cette parenthèse et sa correspondante.
| * Insérer la "depth ième" chaine de mm-big-liste avant la
| parenthèse et sa correspondante.
|_____ __
8<------8<------8<------8<------8<------8<------8<------8<------8<------


Un code elisp mal foutu mais qui fonctionne :


8<------8<------8<------8<------8<------8<------8<------8<------8<------
(defun paren-depth-at-point (begin)
;;Retourne la profondeur du point dans les parenthèses
(save-excursion
(let ((thedepth -1) (notbegin t))
(if (eq ?) (char-after (point)))
(backward-char 1))
(while (and (>= (point) begin) notbegin);;Problème avec le début
;;du buffer
(if (eq ?( (char-after (point)))
(incf thedepth)
(if (eq ?) (char-after (point)))
(decf thedepth)))
(if (not (bobp)) (backward-char 1) (setq notbegin nil))
)
thedepth)))

(defun paren-max-depth-region (beginr endr)
;;Retourne le profondeur maximale des parenthèses de la région
(interactive "r")
(save-excursion
(let ((max-depth 0) (curr-depth 0))
(goto-char beginr)
(while (and (< (point) endr) (re-search-forward "(" nil t 1))
(setq curr-depth (paren-depth-at-point beginr))
(if (> curr-depth max-depth)
(setq max-depth curr-depth)))
max-depth)))

(defvar mm-big-liste '("" "big" "Big" "bigg" "Bigg"))

(defun match-paren-point ()
(let ((pos 0))
(match-paren 1)
(setq pos (point))
(match-paren 1)
pos))

(defun big-paren-region (beginr endr)
;;Converti la région avec les big
(interactive "r")
(let ((list mm-big-liste) (maxdepth 0) (paren-size 0))
(narrow-to-region beginr endr)
(goto-char beginr)
(when (re-search-forward "(*)" nil t 1)
(setq maxdepth (paren-max-depth-region beginr endr));;Prof max
(if (< maxdepth 5)
(progn
(goto-char beginr)
(while (re-search-forward "(" nil t 1)
(backward-char 1)
(setq paren-size (paren-max-depth-region (point) (match-paren-point)))
(insert (nth paren-size list))
(match-paren 1)
(insert (nth paren-size list))
(match-paren 1)
(forward-char 1)
))
(message "Profondeur maximale dépassée..."))
(widen);;En cas de pb C-x n w
)))
8<------8<------8<------8<------8<------8<------8<------8<------8<------

Un exemple simple:
(()(()))----(())

M-x big-paren-region <RET> donne :
Big(()big(()big)Big)----big(()big)

Un exemple plus compliqué :
( ( () ) () )--(( ( ) )()-( ( ( ) ) )-( ) )

M-x big-paren-region <RET> donne :
Big( big( () big) () Big)--bigg(big( ( ) big)()-Big( big( ( ) big) Big)-( ) bigg)


Voilà, je pense que le résultat est maintenant parfait.
Ceci dit, je ne connais pas assez elisp pour coder plus proprement...
--
Philippe.
Avatar
drkm
Ph. Idlavi wrote:

Voilà, je pense que le résultat est maintenant parfait.
Ceci dit, je ne connais pas assez elisp pour coder plus proprement...



À première vue, il n'a pas l'air si mal que cela ... Si j'avais eu
un peu de temps, j'aurais bien regardé d'un peu plus près, mais si
cela marche, j'ai malheureusement d'autres choses à faire. Une
remarque, cependant. J'ai vu que tu as la bonne habitude de commenter
tes fonctions. Mais si au lieu de :

(defun ma-fonction ()
;; La documentation.
...

tu écris :

(defun ma-fonction ()
"La documentation."
...

Emacs lui-même connaîtera la documentation de la fontion. Ce qui te
permet d'utiliser par exemple 'C-h f ma-fonction <RET>' pour en savoir
plus sur ta fonction :-).

--drkm
1 2