Attachment 'findandreplace0.1Beta.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - findandreplace action
4
5 @copyright: 2006 Richard Flieger
6 @contact: < e DASH mail AT rf DASH mmx DOT de >
7 @license: GNU GPL, see COPYING for details.
8
9 Description:
10 This action allows users to search words and
11 sentenses on the current wiki-page and replace
12 the results by another text.
13
14 Feathers:
15 * regulare expressions
16 * wildcard character
17 * fixed strings
18 * show results
19 * show context
20 * highlight in page
21 * show raw-text
22 * toggle highlightning
23 * replace selected
24 * replace all
25 * preview
26 * custumend comment
27 * trivial change or not
28 * language support
29
30 History:
31 2007/03/11 0.1b: Beta, dirty hack
32
33 """
34
35 from MoinMoin.Page import Page
36 from MoinMoin import PageEditor
37 from MoinMoin.widget.dialog import Dialog
38 from re import *
39 import re
40 import shutil
41 import time
42
43 class FindAndReplaceAction:
44
45 def __init__(self, request, referrer):
46 self.request = request
47 self.referrer = referrer
48 self._ = request.getText
49
50 def render( self ):
51
52 self.form = self.request.form
53
54 self.currentusername = self.request.page.page_name
55
56 if not self.request.user.may.read(self.currentusername) or self.form.has_key(u'cancel_button'):
57 query = {'action': 'show'}
58 url = Page(self.request, self.referrer).url(self.request, query, 0)
59 self.request.http_redirect(url)
60
61 self.find = self.form.get('find', [None] )[0]
62 self.replace = self.form.get('replace', [""] )[0]
63 self.methode = self.form.get('methode', ["text"])[0]
64 self.casesensitive = self.form.get( 'casesensitive', [0])[0]
65 self.word = self.form.get('word', [None])[0]
66 self.context = self.form.get('context', [0])[0]
67 self.selected = self.form.get('selected', [])
68 self.comment = self.form.get('comment', [""] )[0]
69 self.highlight = self.form.get( 'highlight',[""] )[0]
70 self.multiline = self.form.get( "multiline", [""])[0]
71 self.searchonly = self.form.get( "searchonly", [""])[0]
72 self.trivial = self.form.get( "trivial", [0] )[0]
73 self.showraw = self.form.get( "showraw", [0] )[0]
74
75 if not self.request.user.may.write(self.currentusername):
76 self.showraw = 0
77 self.contextsize = 20
78
79 if not self.context:
80 self.contextsize = 0
81
82 self.userhelp = self._("""
83 = Help =
84
85 == Regulare expressions ==
86
87 alternation:: A vertical bar separates alternatives. For example, "gray|grey", which could be shortened to the equivalent "gr(a|e)y", can match "gray" or "grey".
88 grouping:: Parentheses are used to define the scope and precedence of the operators. For example, "gray|grey" and "gr(a|e)y" are different patterns, but they both describe the set containing gray and grey.
89 quantification:: [[BR]]A quantifier after a character or group specifies how often that preceding expression is allowed to occur. The most common quantifiers are ?, *, and +:[[BR]]'''?''' The question mark indicates there is 0 or 1 of the previous expression. For example, "colou?r" matches both color and colour.[[BR]]'''*''' The asterisk indicates there are 0, 1 or any number of the previous expression. For example, "go*gle" matches ggle, gogle, google, gooogle, etc.[[BR]]'''+''' The plus sign indicates that there is at least 1 of the previous expression. For example, "go+gle" matches gogle, google, gooogle, etc. (but not ggle).
90
91 ''for detailt look at: [http://en.wikipedia.org/wiki/Regular_Expressions Wikipedia]''
92 == Wildcard character ==
93 The asterisk (*) usually substitutes as a wildcard character for any zero or more characters, and the question mark (?) usually substitutes as a wildcard character for any one character
94
95 ''for detailt look at: [http://en.wikipedia.org/wiki/Wildcard_character Wikipedia]''
96 """)
97
98 self.lang_dict = {
99 ##Headlines
100 u"title_searchtext_text" : self._('''Search Text'''),
101 u"title_findandreplace_text" : self._( '''find and replace''' ),
102
103 ##Menu Text
104 u"text_raw_text" : self._('''Raw'''),
105 u"text_method_text" : self._('''Methode:'''),
106 u"text_option_text" : self._('''Options:'''),
107 u"text_context_text" : self._('''Display context of search results'''),
108 u"text_search_text" : self._( '''Find what''' ),
109 u"text_replace_text" : self._( '''Replace with''' ),
110 u"text_text_text" : self._( '''Fixed string''' ),
111 u"text_word_text" : self._( '''Whole words''' ),
112 u"text_wildcards_text" : self._( '''Wildcard character''' ),
113 u"text_casesensitive_text" : self._( '''Case-sensitive''' ),
114 u"text_regularexpression_text" : self._( '''Regular expressions'''),
115 u"text_Wrap search_text" : self._('''Wrap search'''),
116 u"text_comment_text" : self._('''Comment'''),
117 u"text_multiline_text" : self._('''Multiline'''),
118 u"text_searchonly_text" : self._('''Search only'''),
119 u"text_notsaved_text" : self._('''Your changes are not saved!'''),
120 u"text_saved_text" : self._('''Thank you for your changes. Your attention to detail is appreciated.'''),
121 u"text_trivial_text" : self._('''Trivial change'''),
122 u"text_langcomment_text" : self._('''"%s" replaced by "%s"'''),
123 u"text_showraw_text" : self._('''Show raw Text'''),
124
125 u"text_match_text" : self._('''%(matchcount)d %(matches)s for "%(title)s"'''),
126
127 ##Buttons
128 u"highlight_button" : self._( '''Highlight on/off''' ),
129 u"search_button" : self._( '''Search''' ),
130 u"cancel_button" : self._( '''Cancel''' ),
131 u"preview_button" : self._( '''Preview''' ),
132 u"replaceall_button" : self._( '''Replace all''' ),
133 u"replaceselected_button" : self._( '''Replace selected''' ),
134 u"help_button" : self._('''help'''),
135 u"about_button" : self._('''about''' )
136 }
137
138 self.regex_dict = { u'%3F' : u'?',
139 }
140
141 self.wildcard_dict = { u'''?''' : u'''.''',
142 u'''*''' : u'''.*?''' }
143
144 self.normal_dict = { ##u'''\\''' : u'''\\\\''',
145 u'''.''' : u'''\\.''',
146 u'''*''' : u'''\\*''',
147 u'''[''' : u'''\\[''',
148 u''']''' : u'''\\]''',
149 u'''(''' : u'''\\(''',
150 u''')''' : u'''\\)''' }
151
152 if self.form.has_key(u"help_button" ):
153 self.generateHelpMessage()
154
155 if self.form.has_key(u"about_button" ):
156 self.generateAboutMessage()
157
158 ##Search Action
159 if not self.find and not self.replace:
160 msg = self.generateSearchDialog()
161 page = Page(self.request, self.referrer )
162 page.send_page(self.request, msg=msg )
163 return ''
164
165 if self.form.has_key(u"highlight_button") or self.form.has_key(u"search_button") or self.form.has_key(u"selected_button") or self.form.has_key(u"preview_button") or self.form.has_key(u"all_button"):
166
167 if self.request.user.may.read(self.currentusername):
168 self.getFindRegex()
169
170 if self.form.has_key(u"highlight_button") or self.form.has_key(u"search_button"):
171
172 oldtext = self.getPageText( self.referrer)
173 results = self.findallResults( oldtext )
174 if not results:
175 msg = self.generateNoResultMessage()
176 page = Page(self.request, self.referrer )
177 page.send_page(self.request, msg=msg )
178 return ''
179 else:
180 p = Page(self.request, self.referrer)
181 rev = p.get_real_rev()
182 msg = self.generateReplaceDialog( rev, results )
183
184 page = Page(self.request, self.referrer )
185 page.send_page(self.request, msg=msg )
186 return u""
187
188 if not self.comment:
189 self.comment = (u'''%(text_langcomment_text)s''' % self.lang_dict) % ( self.find, self.replace )
190
191 p = Page(self.request, self.referrer)
192 newrev = p.get_real_rev()
193
194 rev = int(self.form.get( u"rev", 0 )[0])
195
196 if rev == newrev:
197 self.oldtext = self.getPageText(self.referrer)
198 else:
199 query = {'action': 'findandreplace'}
200 url = Page(self.request, self.referrer).url(self.request, query, 0)
201 self.request.http_redirect(url)
202
203 newtext = 0
204
205 if self.form.has_key( u"all_button" ):
206 newtext = self.replaceAll()
207
208 elif self.form.has_key( u"selected_button" ):
209 if self.selected:
210 newtext = self.replaceSelected()
211 else:
212 return 0
213
214 if newtext == 0 or newtext == self.oldtext:
215 query = {'action': 'show'}
216 url = Page(self.request, self.referrer).url(self.request, query, 0)
217 self.request.http_redirect(url)
218
219 page = PageEditor.PageEditor(self.request, self.referrer, do_editor_backup=0)
220 newtext = page.normalizeText(newtext)
221 p = Page(self.request, self.referrer)
222 print rev
223 rev = int(newrev )
224 print rev
225 try:
226 page.saveText(newtext, rev, comment=self.comment, trivial=self.trivial)
227 msg = "%(text_saved_text)s" % self.lang_dict
228 except:
229 msg = "%(text_notsaved_text)s" % self.lang_dict
230 page = Page(self.request, self.referrer )
231 page.send_page(self.request, msg=msg )
232
233 return ''
234
235 def getFindRegex(self):
236
237 self.findregex = self.find
238 if self.methode == "regex":
239 for entry in self.regex_dict:
240 self.findregex = self.findregex.replace( entry, self.regex_dict[entry] )
241
242 elif self.methode == "wildcards":
243 for entry in self.wildcard_dict:
244 self.findregex = self.findregex.replace( entry, self.wildcard_dict[entry] )
245
246 else:
247 for entry in self.normal_dict:
248 self.findregex = self.findregex.replace( entry, self.normal_dict[entry] )
249 if self.word == "1":
250 self.findregex = u'\\b%s\\b' % self.findregex
251
252 if not self.casesensitive:
253 ignorcase = "i"
254 else:
255 ignorcase = ""
256
257 if self.multiline:
258 multiline = u"sm"
259 else:
260 multiline = u""
261
262 if multiline or ignorcase:
263 pattern = u"(?%(m)s%(i)s)" % {u"i" : ignorcase,
264 u"m" : multiline }
265 else:
266 pattern = ""
267
268 self.findregex = u"%(p)s%(f)s" % { u"p" : pattern, u"f" : self.findregex}
269
270 def getPageText(self, pagename ):
271 oldtext = PageEditor.PageEditor(self.request, pagename , do_editor_backup=0)
272 return oldtext.get_raw_body()
273
274 def replaceSelected(self):
275 pattern = re.compile( self.findregex)
276 resultlist = pattern.findall( self.oldtext)#, self.casesensitive )
277 index = 0
278 newtext = self.oldtext
279 pos1 = newtext.find(resultlist[0])
280 for result in resultlist:
281 pos2 = newtext[pos1:].find(result)
282 pos2 = pos1 + len(result)
283 if str(index) in self.selected:
284 newtext = newtext[:pos1] + self.replace + newtext[pos2:]
285 pos1 = pos2 + newtext[pos2:].find(result)
286 index += 1
287 return newtext
288
289 def replaceAll(self):
290 newtext=re.sub(self.findregex, self.form.get(u"replace",[u""])[0], self.oldtext )
291 return newtext
292
293 def parsText( regex, source ):
294 variable = re.search( regex, source )
295 regex = regex.replace('\+|\.', '.')
296 if variable != None:
297 variable = variable.group( 1 )
298 value = variable.decode("iso-8859-1")
299 else:
300 value = u"N/A"
301 return value
302
303 def findallResults(self, text ):
304 pattern = re.compile( self.findregex)#, self.casesensitive )
305 resultList = pattern.findall( text)
306 pos = 0
307 newresultList = []
308 for result in resultList:
309 pos = text.find(result,pos)
310 if pos > self.contextsize:
311 pos1 = pos - self.contextsize
312 else:
313 pos1 = 0
314 pos2 = pos + len(result) + self.contextsize
315 newresultList.append( (text[pos1:pos], result,text[pos+len(result):pos2]) )
316 pos += len(result) +1
317 return newresultList
318
319 def generateReplaceDialog( self, rev, list ):
320 html =[]
321 if len(list) > 1:
322 matches = self._("""matches""")
323 else:
324 matches = self._("""match""")
325 html.append(( u'<b>"%(text_match_text)s</b><br><br>' % self.lang_dict) % { u"title" : self.find, u"matchcount" : len( list ), u"matches" : matches } )
326 html.append(u'<form method="post" action="">')
327 index = 0
328 for entry in list:
329 html.append('''<p>''')
330 if not self.searchonly:
331 html.append( u'<input type="checkbox" name="selected" value="%(index)s">' % { u"index" : index } )
332 html.append( u'...%s<strong class="highlight">%s</strong>%s ...</p>' % ( entry[0], entry[1], entry[2] ) )
333 index += 1
334
335
336 if self.showraw:
337 pagetext = self.getPageText(self.referrer)
338 html.append("""<b>%(text_raw_text)s</b></br>""" % self.lang_dict)
339 html.append("""<pre>\n%s\n</pre>""" % pagetext )
340
341 if not self.searchonly:
342 html.append( '''<p>%(text_replace_text)s''' % self.lang_dict )
343 html.append( '''<input type="text" name="replace" size="20" value="%(replace)s"></p>''' % { u"replace" : self.replace })
344
345 print self.trivial
346 if self.trivial:
347 trivialchecked = u"checked=checked"
348
349 else:
350 trivialchecked = u""
351
352 html.append( '''%(text_comment_text)s <input type="text" size="20" name="comment" value="%(comment)s">
353 %(text_trivial_text)s <input type="checkbox" name="trivial" value="1" %(trivialchecked)s>''' % {
354 u"trivialchecked" : trivialchecked,
355 u"comment" : self.comment,
356 u"text_comment_text" : self.lang_dict[u"text_comment_text"],
357 u"text_trivial_text" : self.lang_dict[u"text_trivial_text"] } )
358
359 html.append( '''<input type="hidden" name="replace" value="%(replace)s">
360 <input type="hidden" name="rev" value="%(rev)d">
361 <input type="hidden" name="find" value="%(find)s">
362 <input type="hidden" name="word" value="%(word)s">
363 <input type="hidden" name="methode" value="%(methode)s">
364 <input type="hidden" name="highlight" value="%(findregex)s">
365 <input type="hidden" name="showraw" value="%(showraw)s">
366 <input type="hidden" name="multiline" value="%(multiline)s">
367 <input type="hidden" name="searchonly" value="%(searchonly)s">
368 </p>''' % { u"replace" : self.replace,
369 u"rev" : rev,
370 u"find" : self.find,
371 u"word" : self.word,
372 u"methode" : self.methode,
373 u"context" : self.context,
374 u"findregex" : self.highlight,
375 u"multiline" : self.multiline,
376 u"searchonly" : self.searchonly,
377 u"showraw" : self.showraw,
378 } )
379 html.append('''<p>''')
380
381 if not self.searchonly:
382 html.append( '''<input type="hidden" name="action" value="findandreplace">
383 <input type="submit" name="preview_button" value="%(preview_button)s">''' % self.lang_dict)
384
385 html.append( '''<input type="submit" name="selected_button" value="%(replaceselected_button)s">
386 <input type="submit" name="all_button" value="%(replaceall_button)s">''' % self.lang_dict )
387
388 html.append( '''<input type="submit" name="cancel_button" value="%(cancel_button)s"></p>
389 ''' % self.lang_dict)
390
391 html.append( '''</div></form>''')
392
393 if not self.highlight:
394 self.highlight = self.findregex
395 else:
396 self.highlight = u""
397
398 html.append( '''<form method="post" action="">
399 <input type="hidden" name="replace" value="%(replace)s">
400 <input type="hidden" name="rev" value="%(rev)d">
401 <input type="hidden" name="find" value="%(find)s">
402 <input type="hidden" name="word" value="%(word)s">
403 <input type="hidden" name="methode" value="%(methode)s">
404 <input type="hidden" name="highlight" value="%(findregex)s">
405 <input type="hidden" name="comment" value="%(comment)s">
406 <input type="hidden" name="multiline" value="%(multiline)s">
407 <input type="hidden" name="searchonly" value="%(searchonly)s">
408 <input type="hidden" name="showraw" value="%(showraw)s">
409 </p>''' % { u"replace" : self.replace,
410 u"rev" : rev,
411 u"find" : self.find,
412 u"word" : self.word,
413 u"methode" : self.methode,
414 u"comment" : self.comment,
415 u"context" : self.context,
416 u"findregex" : self.highlight,
417 u"multiline" : self.multiline,
418 u"searchonly" : self.searchonly,
419 u"showraw" : self.showraw
420 } )
421 if self.trivial:
422 html.append( """<input type="hidden" name="trivial" value="1">""" )
423
424 if self.casesensitive:
425 html.append( '''<input type="hidden" name="casesensitive" value="%(casesensitive)s">''' % {u"casesensitive" : self.casesensitive,} )
426
427 if self.context:
428 html.append( '''<input type="hidden" name="context" value="%(context)s">''' % {u"context" : self.context, } )
429
430 html.append( '''<input type="hidden" name="action" value="findandreplace">
431 <input type="submit" name="highlight_button" value="%(highlight_button)s"></form>
432 ''' % self.lang_dict)
433 return Dialog (self.request, content=u"\n".join( html ) )
434
435 def generateNoResultMessage( self ):
436 return self._(u'''Nothing found for "%s"!''') %(self.find)
437
438 def generateSearchDialog(self):
439
440 html = u'''<b>%(title_findandreplace_text)s</b><br/>
441 %(title_searchtext_text)s<br/>
442 <form method="get" action=""><div>
443 <input type="hidden" name="action" value="findandreplace">
444 <table border=0px>
445 <tr>
446 <td align="right" valign="middle">
447 %(text_search_text)s: <input type="text" name="find" size="20"><br/>
448 %(text_replace_text)s: <input type="text" name="replace" size="20"><br/>
449 %(text_comment_text)s: <input type="text" name="comment" size="20">
450 </td>
451 <td align="left" valign="middle">
452 <p>%(text_option_text)s</p>
453 <input type="checkbox" name="word" value="1">
454 %(text_word_text)s<br/>
455 <input type="checkbox" name="multiline" value="1">
456 %(text_multiline_text)s<br/>
457 <input type="checkbox" name="casesensitive" value="1">
458 %(text_casesensitive_text)s<br/>
459 <input type="checkbox" name="context" value="1">
460 %(text_context_text)s<br/>
461 <input type="checkbox" name="showraw" value="1">
462 %(text_showraw_text)s<br/>
463 <input type="checkbox" name="trivial" value="1">
464 %(text_trivial_text)s<br/>
465 </td>
466 <td>
467 <p>%(text_method_text)s</p>
468 <input type="radio" name="methode" value="none" checked="checked">
469 %(text_text_text)s<br/>
470 <input type="radio" name="methode" value="wildcards">
471 %(text_wildcards_text)s<br/>
472 <input type="radio" name="methode" value="regex">
473 %(text_regularexpression_text)s<br/>
474 </td>
475 </tr>
476 <tr>
477 <td valign="bottom">
478 <p><input type="checkbox" name="searchonly" value="1"> %(text_searchonly_text)s</p>
479 <input type="submit" name="search_button" value="%(search_button)s">
480 <input type="submit" name="cancel_button" value="%(cancel_button)s">
481
482 <input type="submit" name="help_button" value="%(help_button)s">
483 <input type="submit" name="about_button" value="%(about_button)s">
484 </td>
485 </tr>
486 </table>
487 </div></form><br>
488 ''' % self.lang_dict
489
490 return Dialog (self.request, content=html)
491
492 def generateHelpMessage(self):
493 msg = self.userhelp
494 page = Page(self.request, self.referrer )
495 page.send_page(self.request, msg=msg )
496
497 def generateAboutMessage(self):
498 msg = "<pre>%s</pre>" % __doc__
499 page = Page(self.request, self.referrer )
500 page.send_page(self.request, msg=msg )
501
502
503 def execute( pagename, request ):
504 return FindAndReplaceAction( request, pagename ).render()
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.