2009-06-17

emacs string replacement

On Jun 17, 1:34 pm, Michal wrote:
> Hallo Group Members
>
> I have a string which contains national characters and I would like to
> convert them to ASCII equivalents.
>
> for example:
> ó -> o
> ³ -> l
> ¿ -> z
>
> etc.
>
> one of ways is just using:
> (replace-regexp-in-string "ó" "o" my_string)
>
> for each national character, but I believe that there is much better
> way.

here's my solution. I frequently need to replace several pairs, for many applications. e.g. html encoding, url encoding, alpha beta gamma to α β γ, Infinity and Pi to ∞ π, C-x to Ctrl+x and M- to Alt+ , text replacement based basic math formula syntax transform between langs... etc.

Here's the 4 basic functions i call in my other elisp programs.

(defun replace-pairs-in-string (str pairs)
"Replace string STR recursively by find/replace pairs PAIRS sequence.

Example:
(replace-pairs-in-string \"abcdef\"
'([\"a\" \"1\"] [\"b\" \"2\"] [\"c\" \"3\"])) ⇒ “\"123def\"”.
The replacement is done recursively after each find/replace pair.
Earlier replaced value may be replaced again.
The replacement are literal and case sensitive.

If you want the replacement to be case sensitive, set the global variable case-fold-search to nil. Like this: (let ((case-fold-search nil)) (replace-regexp-in-string-pairs ...)

This function calls `replace-regexp-in-string' to do its work.

See also `replace-regexp-pairs-in-string'."
(let ((mystr str))
(setq mystr str)
(mapc
(lambda (x) (setq mystr (replace-regexp-in-string
(regexp-quote (elt x 0))
(elt x 1) mystr t t)))
pairs)
mystr))

(defun replace-regexp-pairs-in-string (str pairs &optional fixedcase)
"Replace string STR recursively by regex find/replace pairs PAIRS sequence.

Form:
(replace-regexp-in-string-pairs
'([REGEX1 REPLACE1] [REGEX2 REPLACE2] ...)
FIXEDCASE)

The PAIRS can be any lisp sequence data type.

The third argument FIXEDCASE, if non-nil, changes the case of the replacement in a smart way matching the letter case of the find string.

If you want the regex to be case sensitive, set the global variable case-fold-search to nil. Like this: (let ((case-fold-search nil)) (replace-regexp-in-string-pairs ...)

This function calls `replace-regexp-in-string' to do its work.

See also `replace-pairs-in-string'."
(let ((mystr str))
(setq mystr str)
(mapc
(lambda (x) (setq mystr (replace-regexp-in-string
(elt x 0)
(elt x 1) mystr fixedcase)))
pairs)
mystr))

(defun replace-pairs-region (start end pairs)
"Replace regex string find/replace PAIRS in region.

For detail, see `replace-pairs-in-string'."
(let (mystr)
(setq mystr (buffer-substring-no-properties start end))
(delete-region start end)
(insert (replace-pairs-in-string mystr pairs))))

(defun replace-regexp-pairs-region (start end pairs &optional fixedcase)
"Replace regex string find/replace PAIRS in region.

For detail, see `replace-regexp-pairs-in-string'."
(let (mystr)
(setq mystr (buffer-substring-no-properties start end))
(delete-region start end)
(insert (replace-regexp-pairs-in-string mystr pairs fixedcase))))


so i have about 10 other functions that does replacement of various types by calling one of the above.

if all you want is just something one-time, as opposed to the above more general functions, pls see:


Q: How to replace “&” by “&” in a region?

Place the following in your emacs init file:

(defun replace-string-pairs-region (start end mylist)
"Replace string pairs in region."
(save-restriction
(narrow-to-region start end)
(mapc
(lambda (arg)
(goto-char (point-min))
(while (search-forward (car arg) nil t) (replace-match (cadr arg)) )
) mylist
)
)
)

(defun replace-html-chars (start end)
"Replace “<” by “<” and other similar HTML chars that needs to be encoded."
(interactive "r")
(replace-string-pairs-region start end '(
("&" "&")
("<" "<")
(">" ">")
)
)
)

With the above code, you can select a region, then press “Alt+x replace-html-chars”, and have all “&”, “>”, “<” replaced by their encoded entity. You can define a keyboard shortcut for easy operation.

You can also use the code to replace some HTML entities by their actual unicode characters. For example:

“ → “
” → ”
é → é
© → ©

-> → →
=> → ⇒
Pi → π
Infinity → ∞

This makes the HTML source code more elegant and readible. (You need to declare your charset as one of unicode encodings. See Character Sets and Encoding in HTML)

above from:

• Emacs and HTML Tips
http://xahlee.org/emacs/emacs_html.html

emacs string replacement can be tricky, due to emacs's feature of smartly choosing letter case plus a weired way to toggle it. (usually using a global var instead of a function parameter, but not always because ...) Emacs regex can also be tricky because it's diff from Perl or posix and in particular has severe toothpick syndrom that basically doesn't exist in any other lang. For some detail, see:

• Find and Replace with Emacs
http://xahlee.org/emacs/emacs_find_replace.html

• Text Pattern Matching in Emacs
http://xahlee.org/emacs/emacs_regex.html

Xah
∑ http://xahlee.org/

No comments:

Post a Comment