📜 ⬆️ ⬇️

PyRoge regular debugger

Hi,% username%, if you also suffer from constant problems with typing regular expressions in python - you are here!
Often in the work I am confronted with writing regular expressions, and constantly experienced some discomfort with their debugging. There are lots of different debuggers in the world, but the problem is that there are different dialects for regulars, for example, by taking regular expressions from Ruby, you cannot run it in Python ( although it would seem that the brothers) . Therefore, I wrote a small program in Python, which allowed me to quickly solve problems on the profile. The logic of the program, peeped somewhere on the Internet (there was a debugger for Ruby). Yes, I also decided to comment on the code, because its a bit, but for the most impatient links to the sources here .
As an initial example, the solution to your favorite timurv task is loaded - continue the Look-And-Say sequence . It looks "approximately" like this:


Tested on Python2.5, PyQt4.4, on Windows Xp, Ubuntu 9.10 machines.

if __name__ == "__main__" :
app = QtGui. QApplication ( sys . Argv )
ui = Ui_mwd ( )
form = Wnd ( ui )
ui. setupUi ( form )
form. show ( )
form. callSearchRegExp ( ) # for first time evalution
sys . exit ( app. exec_ ( ) )

ui_Wnd is a class that modifies an instance of the QtGui.QMainWindow class - generated automatically by pyuic. Wnd is my descendant of QMainWindow , about it below. PyQt is a bit inconvenient - if you look at, all the controls that are hanging on the window belong to the ui_Wnd class, but if we define events in the same QtDesigner, they will fall on the QMainwindow child, so there is such confusion in the code and the need to send Wnd (ui) - that we in our Wnd class could contact the controls.
')
class Wnd ( QtGui. QMainWindow ) :
_timer = None
SIGNAL_prepared = QtCore. SIGNAL ( 'prepared (QString)' )
SIGNAL_excRaise = QtCore. SIGNAL ( 'exceptionRaise (QString)' )
_observer = ObserveHtmlWidget ( )

def __init__ ( self , ui ) :
QtGui QMainWindow . __init__ ( self )
self . ui = ui
QtCore. QObject . connect ( self , self . SIGNAL_prepared , self . onPrepared )
QtCore. QObject . connect ( self , self . SIGNAL_excRaise , self . onRaiseException )

def callSearchRegExp ( self ) :
txt, rg = unicode ( ( self . ui . eText . toPlainText ( ) ) ) , unicode ( self . ui . eReg . toPlainText ( ) )
self . ui . statusBar . clearMessage ( )
try :
data = self ._observer ( txt, rg )
except SmartError, e:
self . emit ( self . SIGNAL_excRaise , e [ 0 ] ) ;
return

if ( data ) :
self . emit ( self . SIGNAL_prepared , data [ 0 ] )
self . showGroups ( data [ 1 ] )

def callTimerForRegExp ( self ) :
if ( self ._timer ) :
self ._timer. cancel ( )
self ._timer = threading . Timer ( 1 , self . CallSearchRegExp )
self ._timer. start ( )

def onPrepared ( self , value ) :
self . ui . eHtml . setHtml ( value )

def onRaiseException ( self , value ) :
self . ui . statusBar . showMessage ( value )

def showGroups ( self , rows ) :
self . ui . lvas . clear ( )
for e in rows:
if isinstance ( e, tuple ) :
prepared = [ inverseReplace ( i ) for i in e ]
self . ui . lvas . addItem ( ',' . join ( prepared ) )
else :
self . ui . lvas . addItem ( inverseReplace ( e ) )

This is the main window class, in principle everything is transparent here:
_timer is a device that allows you to follow the end of the input.
a pair of signals to alert the main program thread that regexp was calculated or not calculated in the background
observer - actually counting machine

callTimerForRegExp - waits for a second to pass, after entering the last character and calls callSearchRegExp , it already calls the counting machine, which returns to the window either regexp data or declared Exception - about the correct error, inside the program. showGroups - this thing allows you to correctly draw the groups that will be found on a regular basis.

# advanced regexp evaluting
class ObserveHtmlWidget ( object ) :
phtml = '& lt; span style = "background-color: # BFE4FF; color: # 0066B3; padding: 2px;" & gt;% s & lt; / span & gt;'
def _exec ( self , func, value, ignoreExc ) :
try :
value = func ( value )
except ignoreExc, e:
raise SmartError ( '% s:% s' % ( type ( e ) .__ name__, e [ 0 ] ) )
return value

def __call__ ( self , text = '' , regexp = '' ) :
if regexp == '' :
return
html, groups = '' , [ ]

text, regexp = htmlReplace ( text ) , protectedReplace ( regexp )
ptn = self ._exec ( re . compile , regexp, re . error )
matches = self ._exec ( ptn. search , text, Exception )
while ( matches and text <> '' ) :
s, e, v = matches. start ( ) , matches. end ( ) , matches. group ( )
groups. append ( matches. groups ( ) )
html + = text [ : s ] + self . phtml % v
if not e 0 :
text = text [ 1 : ]
else : # null valued iterations
text = text [ e: ]
matches = ptn. search ( text )
return ( html + text, groups )


This is actually a calculator, it gets the text and regular text to it, then it runs on matches, and if everything is OK, it returns the text with highlighted matches, and a list of groups. If an error occurs , the correct instance of the SmartError error is returned .

# make simple replace
class HtmlReplacer ( object ) :
mods = { '>' : '& gt;' , '<' : '& lt;' }
def __call__ ( self , raw ) :
for k, v in self . mods . iteritems ( ) :
raw = raw. replace ( k, v )
return raw

# make replace in regexp
class ProtectedHtmlReplacer ( HtmlReplacer ) :
mods = { ' \> ' : '& gt;' , ' \ < ' : '& lt;' }

# inverse replace
class InverseHtmlReplacer ( HtmlReplacer ) :
mods = { '& gt;' : '>' , '& lt;' : '<' }

make call easier
htmlReplace, protectedReplace, inverseReplace = HtmlReplacer ( ) , ProtectedHtmlReplacer ( ) , InverseHtmlReplacer ( )

# this project valid exception
class SmartError ( Exception ) : pass


Well, this is a free application to the code, replacing html tags, because on the control window that highlights the text, it uses html-mode, and in order to correctly display the characters <>, you have to change them to the corresponding html codes.

The project is fully available here .

Source: https://habr.com/ru/post/85361/


All Articles