Visual REGEXP, by Laurent Riesterer, is a program that illustrates the mechanics of regular expressions, quickly build efficient regular expressions, etc. Currently at
My raving was deleted, but I reiterate it: never mind similar tools: this app can be improved, but it can't be beaten.RLH: I use this app all the time. I have tweaked it (wider buttons and a quit button) but other than that I really like it.aspect: as of 2015-02-26 I have made some tiny tweaks for this so I don't have to be this guy. They are hiding behind the discussion tag below, as the 16k-char base64 encoded image on one line made fossil treat the file as binary. Thanks to LW and RLH for encouraging me to actually post this:
--- visual_regexp-3.1.tcl 2006-03-08 12:21:56.000000000 +1100
+++ visual_regexp-3.2.tcl 2015-11-04 09:19:31.019661182 +1100
@@ -1,7 +1,20 @@
+#
+# Changelog since 3.1:
+# - remove stale manual undo code (handled by text widgets)
+# - collapse delete/insert into a single replace to leave undo clean
+# - get rid of extra newline from [.t get 1.0 end]
+# - change select buttons in replace mode (only) to insert \\$x in replace.text
+# - tag/colour inserted \\$x in replace.text
+# - default to replace mode
+# - bump version number to 3.2. filename said 3.1; source said 3.0
+#
+# original was downloaded from http://laurent.riesterer.free.fr/regexp/visual_regexp-3.1.tcl
+#
+package require Tk
package require starkit
starkit::startup
-set version 3.0
+set version 3.2
###############################################################################################
#
@@ -68,7 +81,7 @@
# show/hide history windows on startup
set history 0
# mode to use on startup (select/concat = raw, select/insert new lines = nl, replace = replace)
-set mode nl
+set mode replace
# database of some regexp to appear in the "Insert regexp" menu
set regexp_db {
"URL" {(?:^|")(http|ftp|mailto):(?://)?(\w+(?:[\.:@]\w+)*?)(?:/|@)([^"\?]*?)(?:\?([^\?"]*?))?(?:$|")}
@@ -88,8 +101,6 @@
#----------------------------------------------------------------------------------------------
namespace eval regexp {} {
- set data(v:undo:index) 0
- set data(v:undo:sample) ""
set data(v:dir) "."
set data(v:file) "untitled.txt"
@@ -172,13 +183,11 @@
}
}
- if {$tcl_platform(platform) == "windows"} {
- set sfont {Courier 8};
- set sbfont {Courier 8 bold};
- } else {
- set sfont 6x13;
- set sbfont 6x13bold;
- }
+ set sfont TkFixedFont
+ set sbfont TkFixedFontBold
+ set fa [font actual $sfont]
+ dict set da -weight bold
+ font create $sbfont {*}$fa
set data(w:help) [text .top.regexp.help \
-font $sfont \
@@ -191,7 +200,7 @@
.top.regexp.help insert 1.0 "\n\n\n\n\n\n\n\n";
.top.regexp.help insert 1.0 {\a alert \n newline \0 char 0 \d [[:digit:]] \A beginning of the string };
.top.regexp.help insert 2.0 {\b backspace \r carriage \xyz octal code \D [^[:digit:]] \Z end of string };
- .top.regexp.help insert 3.0 {\B synomyn for \ \t tab \s [[:space:]] \m beginning of a word};
+ .top.regexp.help insert 3.0 {\B synonym for \ \t tab \s [[:space:]] \m beginning of a word};
.top.regexp.help insert 4.0 {\cX same as X & 0x1F \uwxyz unicode \x backref \S [^[:space:]] \M end of a word};
.top.regexp.help insert 5.0 {\e ESC \v vert tab \w [[:alnum:]_] \y beginning or end of a word};
.top.regexp.help insert 6.0 {\f form feed \xhhh hexa code \W [^[:alnum:]_] \Y not beginning or end of a word};
@@ -356,6 +365,7 @@
foreach level $data(v:levels) color $colors {
$data(w:regexp) tag configure $level -foreground $color;
+ $data(w:replace) tag configure $level -foreground $color;
$data(w:history) tag configure $level -foreground $color;
$data(w:sample) tag configure $level -foreground $color;
}
@@ -693,6 +703,10 @@
proc regexp::select {level} {
variable data
+ if {$data(v:mode) eq "replace"} {
+ $data(w:replace) insert insert \\\\$level e$level
+ return
+ }
# update
go
if {[llength $data(v:result)] == 0} {
@@ -722,8 +736,7 @@
}
incr i
}
- $data(w:sample) delete 1.0 end
- $data(w:sample) insert 1.0 $newsample
+ $data(w:sample) replace 1.0 end $newsample
# update with regexp
go
}
@@ -809,48 +822,6 @@
}
#----------------------------------------------------------------------------------------------
-# Undo/redo (quick and dirty UNDO/REDO support)
-#----------------------------------------------------------------------------------------------
-
-proc regexp::undo:sample {} {
-variable data
-
- # display result
- $data(w:sample) delete 1.0 end
- $data(w:sample) insert 1.0 $data(v:undo:sample)
- # colorize
- go
-}
-
-proc regexp::unredo:regexp {dir} {
-variable data
-
- set index [expr ($data(v:undo:index)+$dir) % 100]
- if {![info exists data(v:undo:r$index)]} {
- return
- }
- set data(v:undo:index) $index
-
- set t $data(w:regexp)
- $t delete 1.0 end
- $t insert 1.0 [lindex $data(v:undo:r$index) 1]
- $t mark set insert [lindex $data(v:undo:r$index) 0]
-}
-
-proc regexp::undo:regexp:compute {w k a} {
-variable data
-
- if {[string match -nocase "*control*" $k]
- || [string match -nocase "*shift*" $k]
- || [string match -nocase "*alt*" $k]} {
- return
- }
-
- set data(v:undo:r$data(v:undo:index)) [list [$w index insert] [$w get 1.0 end-1char]]
- set data(v:undo:index) [expr ($data(v:undo:index)+1) % 100]
-}
-
-#----------------------------------------------------------------------------------------------
# Replace
#----------------------------------------------------------------------------------------------
@@ -864,23 +835,24 @@
return
}
- # get sample & store it for undo
set sample [$data(w:sample) get 1.0 end]
- set data(v:undo:sample) $sample
- set result [eval regsub $data(v:all) \
- $data(v:line) $data(v:lineanchor) $data(v:linestop) \
- $data(v:nocase) -- \
- [list $exp] [list $sample] [list [subst -nocommands -novariables $subst]] sample]
+ regsub {(.*)\n} $sample {\1} sample
+ set subst [subst -nocommands -novariables $subst]
+
+ set flags [list {*}$data(v:all) {*}$data(v:line) {*}$data(v:lineanchor) {*}$data(v:linestop) {*}$data(v:nocase)]
+ set result [regsub {*}$flags -- $exp $sample $subst sample]
+
set regexp::data(v:nbreplace) "$result replaced"
# display result
- $data(w:sample) delete 1.0 end
- $data(w:sample) insert 1.0 $sample
+ #$data(w:sample) edit separator
+ $data(w:sample) replace 1.0 end $sample
+ #$data(w:sample) edit separator
}
proc regexp::replace:toggle {} {
variable data
- if {$regexp::data(v:mode) == "replace"} {
+ if {$data(v:mode) == "replace"} {
bind $data(w:regexp) <Tab> "focus $data(w:replace); break;"
bind $data(w:regexp) <Shift-Tab> "focus $data(w:sample); break;"
catch { bind $data(w:regexp) <ISO_Left_Tab> "focus $data(w:sample); break;" }
@@ -918,8 +890,7 @@
proc regexp::regexp:set {text} {
variable data
- $data(w:regexp) delete 1.0 end
- $data(w:regexp) insert 1.0 $text
+ $data(w:regexp) replace 1.0 end $text
}
proc regexp::regexp:colorize {} {
@@ -1138,8 +1109,7 @@
proc regexp::sample:set {text} {
variable data
- $data(w:sample) delete 1.0 end
- $data(w:sample) insert 1.0 $text
+ $data(w:sample) replace 1.0 end $text
set data(v:undo:sample) $text
}
@@ -1471,8 +1441,7 @@
variable data
set words [$data(w:make:list) get 1.0 end-1c]
- $data(w:make:output) delete 1.0 end
- $data(w:make:output) insert 1.0 [make-regexp::make-regexp $words]
+ $data(w:make:output) replace 1.0 end [make-regexp::make-regexp $words]
}
proc regexp::make-regexp:ok {w} {