My favorites | Sign in
Project Home Downloads Wiki Issues Source
Repository:
Checkout   Browse   Changes   Clones  
Changes to /packages/xfrp_find_replace_pairs.el
b962d1c4a48f vs. 17503e099a7c Compare: vs.  Format:
Revision 17503e099a7c
Go to: 
Project members, sign in to write a code review
/packages/xfrp_find_replace_pairs.el   b962d1c4a48f /packages/xfrp_find_replace_pairs.el   17503e099a7c
1 ;-*- coding: utf-8 -*- 1 ;-*- coding: utf-8 -*-
2 ;; xfrp_find_replace_pairs.el -- elisp utility for string replacement 2 ;; xfrp_find_replace_pairs.el -- elisp utility for string replacement
3 3
4 ;; Copyright © 2010 by Xah Lee 4 ;; Copyright © 2010 by Xah Lee
5 5
6 ;; Author: Xah Lee ( http://xahlee.org/ ) 6 ;; Author: Xah Lee ( http://xahlee.org/ )
7 ;; Keywords: emacs lisp, string, find replace 7 ;; Keywords: emacs lisp, string, find replace
8 8
9 ;; You can redistribute this program and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either GPL version 2 or 3. 9 ;; You can redistribute this program and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either GPL version 2 or 3.
10 10
11 ;;; DESCRIPTION 11 ;;; DESCRIPTION
12 12
13 ;; this package is a emacs lisp utility. 13 ;; this package is a emacs lisp utility.
14 ;; It provides the following functions: 14 ;; It provides the following functions:
15 15
16 ;; replace-pairs-in-string 16 ;; replace-pairs-in-string
17 ;; replace-regexp-pairs-in-string 17 ;; replace-regexp-pairs-in-string
18 ;; replace-pairs-region 18 ;; replace-pairs-region
19 ;; replace-regexp-pairs-region 19 ;; replace-regexp-pairs-region
20 ;; replace-pairs-in-string-recursive 20 ;; replace-pairs-in-string-recursive
21 21
22 ;; these are convenient functions that lets you do multiple find/replace pairs. 22 ;; these are convenient functions that lets you do multiple find/replace pairs.
23 23
24 ;; For some explanation of the need for these functions, see: 24 ;; For some explanation of the need for these functions, see:
25 ;; http://ergoemacs.org/emacs/elisp_replace_string_region.html 25 ;; http://ergoemacs.org/emacs/elisp_replace_string_region.html
26 26
27 ;; Donation of $3 is appreciated. Paypal to 〔xah@xahlee.org〕 27 ;; Donation of $3 is appreciated. Paypal to 〔xah@xahlee.org〕
28 28
29 ;;; INSTALL 29 ;;; INSTALL
30 30
31 ;; Place the file in your emacs load path. Then 31 ;; Place the file in your emacs load path. Then
32 ;; (require 'xfrp_find_replace_pairs) 32 ;; (require 'xfrp_find_replace_pairs)
33 33
34 ;;; HISTORY 34 ;;; HISTORY
35 35
36 ;; version 1.4.6, 2012-07-05 • fixed several documentation error: mismatched paren in doc.
36 ;; version 1.4.5, 2011-11-12 • added a optional argument to replace-regexp-pairs-region. 37 ;; version 1.4.5, 2011-11-12 • added a optional argument to replace-regexp-pairs-region.
37 ;; version 1.4.4, 2011-10-30 • fix a important error on documentation of replace-regexp-pairs-in-string, about the reversal of its 3rd argument fixedcase. 38 ;; version 1.4.4, 2011-10-30 • fix a important error on documentation of replace-regexp-pairs-in-string, about the reversal of its 3rd argument fixedcase.
38 ;; version 1.4.3, 2011-10-29 • major update on the implementation of “replace-pairs-region”, and minor update on others. No user visible change. 39 ;; version 1.4.3, 2011-10-29 • major update on the implementation of “replace-pairs-region”, and minor update on others. No user visible change.
39 ;; version 1.3, 2011-09-28 • slight change to replace-pairs-in-string to improve speed. The function's user level behavior is the same. 40 ;; version 1.3, 2011-09-28 • slight change to replace-pairs-in-string to improve speed. The function's user level behavior is the same.
40 ;; version 1.2, 2011-08-31 • change made to replace-pairs-region so that inserting occurs only if there are changes made. The function's user level behavior is the same, except the function might be slower when the region's text is large. 41 ;; version 1.2, 2011-08-31 • change made to replace-pairs-region so that inserting occurs only if there are changes made. The function's user level behavior is the same, except the function might be slower when the region's text is large.
41 ;; version 1.1, 2011-03-14. • fixed a doc error in replace-pairs-region. • fixed a code error in replace-regexp-pairs-in-string (this fix has no change in behavior). 42 ;; version 1.1, 2011-03-14. • fixed a doc error in replace-pairs-region. • fixed a code error in replace-regexp-pairs-in-string (this fix has no change in behavior).
42 ;; version 1.0, 2010-08-17. First version. 43 ;; version 1.0, 2010-08-17. First version.
43 44
44 45
45 ;;; Code: 46 ;;; Code:
46 47
47 (defun replace-pairs-in-string (str pairs) 48 (defun replace-pairs-in-string (str pairs)
48 "Replace string STR by find/replace PAIRS sequence. 49 "Replace string STR by find/replace PAIRS sequence.
49 50
50 Example: 51 Example:
51 (replace-pairs-in-string \"abcdef\" 52 (replace-pairs-in-string \"abcdef\"
52 '([\"a\" \"1\"] [\"b\" \"2\"] [\"c\" \"3\"])) ⇒ “\"123def\"”. 53 '([\"a\" \"1\"] [\"b\" \"2\"] [\"c\" \"3\"])) ⇒ “\"123def\"”.
53 54
54 The search strings are not case sensitive. 55 The search strings are not case sensitive.
55 The replacement are literal and case sensitive. 56 The replacement are literal and case sensitive.
56 57
57 If you want search strings to be case sensitive, set 58 If you want search strings to be case sensitive, set
58 `case-fold-search' to nil. Like this: 59 `case-fold-search' to nil. Like this: (let ((case-fold-search nil)) (replace-regexp-in-string-pairs …))
59
60 (let ((case-fold-search nil))
61 (replace-regexp-in-string-pairs …)
62 60
63 Once a subsring in the input string is replaced, that part is not changed again. 61 Once a subsring in the input string is replaced, that part is not changed again.
64 For example, if the input string is “abcd”, and the pairs are 62 For example, if the input string is “abcd”, and the pairs are
65 a → c and c → d, then, result is “cbdd”, not “dbdd”. 63 a → c and c → d, then, result is “cbdd”, not “dbdd”.
66 If you simply want repeated replacements, use `replace-pairs-in-string-recursive'. 64 If you simply want repeated replacements, use `replace-pairs-in-string-recursive'.
67 65
68 See also `replace-regexp-pairs-in-string' and `replace-pairs-region'." 66 See also `replace-regexp-pairs-in-string' and `replace-pairs-region'."
69 ;; code outline. Replace first item in each pair to a unique random string, then replace this list to the desired string. 67 ;; code outline. Replace first item in each pair to a unique random string, then replace this list to the desired string.
70 (let (ξi (myStr str) (tempMapPoints '())) 68 (let (ξi (myStr str) (tempMapPoints '()))
71 ;; generate a random string list for intermediate replacement 69 ;; generate a random string list for intermediate replacement
72 (setq ξi 0) 70 (setq ξi 0)
73 (while (< ξi (length pairs)) 71 (while (< ξi (length pairs))
74 ;; use rarely used unicode char to prevent match in input string 72 ;; use rarely used unicode char to prevent match in input string
75 ;; was using random number for the intermediate string. The problem is: ① there might be collision if there are hundreds or thousands of pairs. ② the random number are too long, even in hex notation, and slows down string replacement. 73 ;; was using random number for the intermediate string. The problem is: ① there might be collision if there are hundreds or thousands of pairs. ② the random number are too long, even in hex notation, and slows down string replacement.
76 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints )) 74 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints ))
77 (setq ξi (1+ ξi)) 75 (setq ξi (1+ ξi))
78 ) 76 )
79 77
80 ;; replace each find string by corresponding item in random string list 78 ;; replace each find string by corresponding item in random string list
81 (setq ξi 0) 79 (setq ξi 0)
82 (while (< ξi (length pairs)) 80 (while (< ξi (length pairs))
83 (setq myStr (replace-regexp-in-string 81 (setq myStr (replace-regexp-in-string
84 (regexp-quote (elt (elt pairs ξi) 0)) 82 (regexp-quote (elt (elt pairs ξi) 0))
85 (elt tempMapPoints ξi) 83 (elt tempMapPoints ξi)
86 myStr t t)) 84 myStr t t))
87 (setq ξi (1+ ξi)) 85 (setq ξi (1+ ξi))
88 ) 86 )
89 87
90 ;; replace each random string by corresponding replacement string 88 ;; replace each random string by corresponding replacement string
91 (setq ξi 0) 89 (setq ξi 0)
92 (while (< ξi (length pairs)) 90 (while (< ξi (length pairs))
93 (setq myStr (replace-regexp-in-string 91 (setq myStr (replace-regexp-in-string
94 (elt tempMapPoints ξi) 92 (elt tempMapPoints ξi)
95 (elt (elt pairs ξi) 1) 93 (elt (elt pairs ξi) 1)
96 myStr t t)) 94 myStr t t))
97 (setq ξi (1+ ξi)) 95 (setq ξi (1+ ξi))
98 ) 96 )
99 97
100 myStr)) 98 myStr))
101 99
102 (defun replace-regexp-pairs-in-string (str pairs &optional fixedcase) 100 (defun replace-regexp-pairs-in-string (str pairs &optional fixedcase)
103 "Replace string STR recursively by regex find/replace pairs PAIRS sequence. 101 "Replace string STR recursively by regex find/replace pairs PAIRS sequence.
104 102
105 The second argument PAIRS should be a sequence of pairs, e.g. 103 The second argument PAIRS should be a sequence of pairs, e.g.
106 [[regexStr1 replaceStr1] [regexStr2 replaceStr2] …] 104 [[regexStr1 replaceStr1] [regexStr2 replaceStr2] …]
107 It can be list or vector. 105 It can be list or vector.
108 106
109 If third arg FIXEDCASE is non-nil, do not alter case of replacement text. 107 If third arg FIXEDCASE is non-nil, do not alter case of replacement text.
110 (same as in `replace-match') 108 (same as in `replace-match')
111 109
112 If you want the regex to be case sensitive, set the global 110 If you want the regex to be case sensitive, set the global
113 variable `case-fold-search' to “nil”. Like this: 111 variable `case-fold-search' to “nil”. Like this: (let ((case-fold-search nil)) (replace-regexp-pairs-in-string …))
114 (let ((case-fold-search nil)) (replace-regexp-pairs-in-string …)
115 112
116 See also `replace-pairs-in-string'." 113 See also `replace-pairs-in-string'."
117 (let ((myStr str)) 114 (let ((myStr str))
118 (mapc 115 (mapc
119 (lambda (x) (setq myStr (replace-regexp-in-string (elt x 0) (elt x 1) myStr fixedcase))) 116 (lambda (x) (setq myStr (replace-regexp-in-string (elt x 0) (elt x 1) myStr fixedcase)))
120 pairs) 117 pairs)
121 myStr)) 118 myStr))
122 119
123 ;; 2011-11-04 implemented using narrow-to-region. 120 ;; 2011-11-04 implemented using narrow-to-region.
124 (defun replace-pairs-region (p1 p2 pairs) 121 (defun replace-pairs-region (p1 p2 pairs)
125 "Replace string find/replace PAIRS in region. 122 "Replace string find/replace PAIRS in region.
126 123
127 Same as `replace-pairs-in-string' except does on a region." 124 Same as `replace-pairs-in-string' except does on a region."
128 (let (ξi (tempMapPoints '())) 125 (let (ξi (tempMapPoints '()))
129 ;; generate a random string list for intermediate replacement 126 ;; generate a random string list for intermediate replacement
130 (setq ξi 0) 127 (setq ξi 0)
131 (while (< ξi (length pairs)) 128 (while (< ξi (length pairs))
132 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints )) 129 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints ))
133 (setq ξi (1+ ξi)) 130 (setq ξi (1+ ξi))
134 ) 131 )
135 (save-excursion 132 (save-excursion
136 (save-restriction 133 (save-restriction
137 (narrow-to-region p1 p2) 134 (narrow-to-region p1 p2)
138 135
139 ;; replace each find string by corresponding item in random string list 136 ;; replace each find string by corresponding item in random string list
140 (setq ξi 0) 137 (setq ξi 0)
141 (while (< ξi (length pairs)) 138 (while (< ξi (length pairs))
142 (goto-char (point-min)) 139 (goto-char (point-min))
143 (while (search-forward (elt (elt pairs ξi) 0) nil t) 140 (while (search-forward (elt (elt pairs ξi) 0) nil t)
144 (replace-match (elt tempMapPoints ξi) t t) ) 141 (replace-match (elt tempMapPoints ξi) t t) )
145 (setq ξi (1+ ξi)) 142 (setq ξi (1+ ξi))
146 ) 143 )
147 144
148 ;; replace each random string by corresponding replacement string 145 ;; replace each random string by corresponding replacement string
149 (setq ξi 0) 146 (setq ξi 0)
150 (while (< ξi (length pairs)) 147 (while (< ξi (length pairs))
151 (goto-char (point-min)) 148 (goto-char (point-min))
152 (while (search-forward (elt tempMapPoints ξi) nil t) 149 (while (search-forward (elt tempMapPoints ξi) nil t)
153 (replace-match (elt (elt pairs ξi) 1) t t) ) 150 (replace-match (elt (elt pairs ξi) 1) t t) )
154 (setq ξi (1+ ξi)) ) ) ) ) ) 151 (setq ξi (1+ ξi)) ) ) ) ) )
155 152
156 (defun replace-pairs-region2 (p1 p2 pairs) 153 (defun replace-pairs-region2 (p1 p2 pairs)
157 "Variant implementation of `replace-pairs-region'. 154 "Variant implementation of `replace-pairs-region'.
158 Implemented using `with-temp-buffer'." 155 Implemented using `with-temp-buffer'."
159 (let (ξi myStr newStr (tempMapPoints '())) 156 (let (ξi myStr newStr (tempMapPoints '()))
160 ;; generate a random string list for intermediate replacement 157 ;; generate a random string list for intermediate replacement
161 (setq ξi 0) 158 (setq ξi 0)
162 (while (< ξi (length pairs)) 159 (while (< ξi (length pairs))
163 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints )) 160 (setq tempMapPoints (cons (format "⚎ด%x" ξi) tempMapPoints ))
164 (setq ξi (1+ ξi)) 161 (setq ξi (1+ ξi))
165 ) 162 )
166 163
167 (setq myStr (buffer-substring-no-properties p1 p2)) 164 (setq myStr (buffer-substring-no-properties p1 p2))
168 (setq newStr 165 (setq newStr
169 (with-temp-buffer 166 (with-temp-buffer
170 (insert myStr) 167 (insert myStr)
171 ;; replace each find string by corresponding item in random string list 168 ;; replace each find string by corresponding item in random string list
172 (setq ξi 0) 169 (setq ξi 0)
173 (while (< ξi (length pairs)) 170 (while (< ξi (length pairs))
174 (goto-char (point-min)) 171 (goto-char (point-min))
175 (while (search-forward (elt (elt pairs ξi) 0) nil t) 172 (while (search-forward (elt (elt pairs ξi) 0) nil t)
176 (replace-match (elt tempMapPoints ξi) t t) ) 173 (replace-match (elt tempMapPoints ξi) t t) )
177 (setq ξi (1+ ξi)) 174 (setq ξi (1+ ξi))
178 ) 175 )
179 176
180 ;; replace each random string by corresponding replacement string 177 ;; replace each random string by corresponding replacement string
181 (setq ξi 0) 178 (setq ξi 0)
182 (while (< ξi (length pairs)) 179 (while (< ξi (length pairs))
183 (goto-char (point-min)) 180 (goto-char (point-min))
184 (while (search-forward (elt tempMapPoints ξi) nil t) 181 (while (search-forward (elt tempMapPoints ξi) nil t)
185 (replace-match (elt (elt pairs ξi) 1) t t) ) 182 (replace-match (elt (elt pairs ξi) 1) t t) )
186 (setq ξi (1+ ξi)) ) 183 (setq ξi (1+ ξi)) )
187 184
188 (buffer-string) )) 185 (buffer-string) ))
189 186
190 (save-excursion 187 (save-excursion
191 (delete-region p1 p2) 188 (delete-region p1 p2)
192 (goto-char p1) 189 (goto-char p1)
193 (insert newStr) 190 (insert newStr)
194 ) 191 )
195 ) ) 192 ) )
196 193
197 (defun replace-pairs-region3 (p1 p2 pairs) 194 (defun replace-pairs-region3 (p1 p2 pairs)
198 "Variant implementation of `replace-pairs-region'. 195 "Variant implementation of `replace-pairs-region'.
199 Implemented by working with string." 196 Implemented by working with string."
200 (let (inputStr newStr) 197 (let (inputStr newStr)
201 (setq inputStr (buffer-substring-no-properties p1 p2)) 198 (setq inputStr (buffer-substring-no-properties p1 p2))
202 (setq newStr (replace-pairs-in-string inputStr pairs)) 199 (setq newStr (replace-pairs-in-string inputStr pairs))
203 200
204 (when (not (string-equal inputStr newStr)) 201 (when (not (string-equal inputStr newStr))
205 (delete-region p1 p2) 202 (delete-region p1 p2)
206 (insert newStr) 203 (insert newStr)
207 ) 204 )
208 )) 205 ))
209 206
210 (defun replace-regexp-pairs-region (p1 p2 pairs &optional fixedcase literal) 207 (defun replace-regexp-pairs-region (p1 p2 pairs &optional fixedcase literal)
211 "Replace regex string find/replace PAIRS in region. 208 "Replace regex string find/replace PAIRS in region.
212 209
213 P1 P2 are the region boundaries. 210 P1 P2 are the region boundaries.
214 211
215 PAIRS is 212 PAIRS is
216 [[regexStr1 replaceStr1] [regexStr2 replaceStr2] …] 213 [[regexStr1 replaceStr1] [regexStr2 replaceStr2] …]
217 It can be list or vector. 214 It can be list or vector.
218 215
219 The optional arguments FIXEDCASE and LITERAL is the same as in `replace-match'. 216 The optional arguments FIXEDCASE and LITERAL is the same as in `replace-match'.
220 217
221 If you want the regex to be case sensitive, set the global 218 If you want the regex to be case sensitive, set the global
222 variable `case-fold-search' to “nil”. Like this: 219 variable `case-fold-search' to “nil”. Like this: (let ((case-fold-search nil)) (replace-regexp-pairs-region …))"
223 (let ((case-fold-search nil)) (replace-regexp-pairs-region …)"
224 (let ( ξi currentPair (pairLength (length pairs))) 220 (let ( ξi currentPair (pairLength (length pairs)))
225 (save-restriction 221 (save-restriction
226 (narrow-to-region p1 p2) 222 (narrow-to-region p1 p2)
227 223
228 (setq ξi 0) 224 (setq ξi 0)
229 (while (< ξi pairLength) 225 (while (< ξi pairLength)
230 (setq currentPair (elt pairs ξi)) 226 (setq currentPair (elt pairs ξi))
231 (goto-char (point-min)) 227 (goto-char (point-min))
232 228
233 (while (search-forward-regexp (elt currentPair 0) (point-max) t) 229 (while (search-forward-regexp (elt currentPair 0) (point-max) t)
234 (replace-match (elt currentPair 1) fixedcase literal) ) 230 (replace-match (elt currentPair 1) fixedcase literal) )
235 (setq ξi (1+ ξi) ) ) ) ) ) 231 (setq ξi (1+ ξi) ) ) ) ) )
236 232
237 (defun replace-regexp-pairs-region-old (p1 p2 pairs &optional fixedcase) 233 (defun replace-regexp-pairs-region-old (p1 p2 pairs &optional fixedcase)
238 "Replace regex string find/replace PAIRS in region. 234 "Replace regex string find/replace PAIRS in region.
239 235
240 For detail, see `replace-regexp-pairs-in-string'." 236 For detail, see `replace-regexp-pairs-in-string'."
241 (let (myStr) 237 (let (myStr)
242 (setq myStr (buffer-substring-no-properties p1 p2)) 238 (setq myStr (buffer-substring-no-properties p1 p2))
243 (delete-region p1 p2) 239 (delete-region p1 p2)
244 (goto-char p1) 240 (goto-char p1)
245 (insert (replace-regexp-pairs-in-string myStr pairs fixedcase)))) 241 (insert (replace-regexp-pairs-in-string myStr pairs fixedcase))))
246 242
247 (defun replace-pairs-in-string-recursive (str pairs) 243 (defun replace-pairs-in-string-recursive (str pairs)
248 "Replace string STR recursively by find/replace pairs PAIRS sequence. 244 "Replace string STR recursively by find/replace pairs PAIRS sequence.
249 245
250 This function is similar to `replace-pairs-in-string', except that 246 This function is similar to `replace-pairs-in-string', except that
251 the replacement is done recursively after each find/replace pair. 247 the replacement is done recursively after each find/replace pair.
252 Earlier replaced value may be replaced again. 248 Earlier replaced value may be replaced again.
253 249
254 For example, if the input string is “abcd”, and the pairs are 250 For example, if the input string is “abcd”, and the pairs are
255 a → c and c → d, then, 251 a → c and c → d, then,
256 252
257 replace-pairs-in-string would return 253 replace-pairs-in-string would return
258 “cbdd” 254 “cbdd”
259 but replace-pairs-in-string-recursive would return 255 but replace-pairs-in-string-recursive would return
260 “dbdd”. 256 “dbdd”.
261 257
262 See `replace-pairs-in-string' for full doc." 258 See `replace-pairs-in-string' for full doc."
263 (let (myStr) 259 (let (myStr)
264 (setq myStr str) 260 (setq myStr str)
265 (mapc 261 (mapc
266 (lambda (x) (setq myStr (replace-regexp-in-string (regexp-quote (elt x 0)) (elt x 1) myStr t t))) 262 (lambda (x) (setq myStr (replace-regexp-in-string (regexp-quote (elt x 0)) (elt x 1) myStr t t)))
267 pairs) 263 pairs)
268 myStr)) 264 myStr))
269 265
270 (provide 'xfrp_find_replace_pairs) 266 (provide 'xfrp_find_replace_pairs)
Powered by Google Project Hosting