#!/bin/sh # txt2regexp.sh - Regular Expressions "wizard" # # A T E N T I O N: only works in bash >= 2.04 # # all REs for the S2_PROG arrays was taken from the PROG man page # or missing it, from the 'mastering regular expressions' book # # versions tested: # ed: GNU ed version 0.2 # egrep: egrep (GNU grep) 2.4.2 # find: GNU find version 4.1 # gawk: GNU Awk 3.0.4 # grep: grep (GNU grep) 2.4.2 # mawk: mawk 1.2 # sed: GNU sed version 3.02.80 # vim: VIM - Vi IMproved 5.7 # # $STATUS: # 0 begining of the regexp # 1 defining regexp # 12 defining type of letters # 2 defining quantifier # 3 end of the regexp # # 20001019 ** 1st version # 20001026 ++ lots of changes and tests # 20001028 ++ improvements, public release # # TODO i18n # TODO capture blanks on Get* (via menu) # TODO create [] mixing letters/numbers/blanks # TODO EscChar - delimiters too? like / (sed, *awk) # TODO expr, oawk, nawk, MKS awk, flex, php # TODO s/vi/n&/ # take out from here programs you don't want to know about # or to minimize the lines printed on the screen #progs=(awk ed egrep emacs expect find gawk grep lex lisp mawk perl python sed tcl vi vim) progs=(egrep emacs gawk grep perl sed vim) set -o noglob # here's all the text and RegExps arrays S0_txt=('comece a casar a partir' 'do começo da linha'\ 'de qualquer lugar da linha') S0_re=('' '^' '') S1_txt=('seguido de' 'apenas números' 'apenas letras' 'letras e números'\ 'um caractere qualquer' 'um caractere específico'\ 'uma lista de caracteres permitidos'\ 'uma lista de caracteres proibidos'\ 'uma cadeia de caracteres literais' 'qualquer coisa') S1_re=( '' '[0-9]' '' '0-9' '.' '' '' '' '' '.*') S12_txt=('tipo das letras' 'apenas letras maiúsculas'\ 'apenas letras minúsculas' 'letras maiúsculas e minúsculas') S12_re=( '' 'A-Z' 'a-z' 'A-Za-z') S2_txt=('quantas vezes' 'uma' 'zero ou uma (opcional)' 'zero ou mais'\ 'uma ou mais' 'exatamente N' 'até N' 'no mínimo N') S2_sed=( '' '' '\?' '*' '\+' '\{@\}' '\{1,@\}' '\{@,\}') S2_ed=( '' '' '\?' '*' '\+' '\{@\}' '\{1,@\}' '\{@,\}') S2_grep=( '' '' '\?' '*' '\+' '\{@\}' '\{1,@\}' '\{@,\}') S2_vim=( '' '' '\=' '*' '\+' '\{@}' '\{1,@}' '\{@,}' ) S2_egrep=( '' '' '?' '*' '+' '{@}' '{1,@}' '{@,}' ) S2_python=('' '' '?' '*' '+' '{@}' '{1,@}' '{@,}' ) S2_lex=( '' '' '?' '*' '+' '{@}' '{1,@}' '{@,}' ) S2_perl=( '' '' '?' '*' '+' '{@}' '{1,@}' '{@,}' ) S2_gawk=( '' '' '?' '*' '+' '{@}' '{1,@}' '{@,}' ) S2_mawk=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_awk=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_find=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_emacs=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_lisp=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_tcl=( '' '' '?' '*' '+' '!!' '!!' '!!' ) S2_expect=('' '' '?' '*' '+' '!!' '!!' '!!' ) S2_vi=( '' '' '\?' '*' '\+' '__' '__' '__' ) #63# cause on table 6-1 it seems that the vi part is wrong # mastering regular expressions: # egrep 29 1-3 # .* 182 6-1 # grep 183 6-2 # *awk 184 6-3 # tcl 189 6-4 # emacs 194 6-7 # perl 201 7-1 # tst: \/_$[]{}()|+?^_/p # [gm]awk = egrep ax_txt=('detalhes' 'agrupamento' 'alternância' 'escapar normal' 'escapar lista []') # \.*[]{}()|+?^$ ,=tested space=pending ax_ed=( '' '\(,\)' '\|' '\.*[,,,,,,,,,,' ',') ax_vim=( '' '\(,\)' '\|' '\.*[,,,,,,,,,,' '\') ax_sed=( '' '\(,\)' '\|' '\.*[,,,,,,,,,,' ',') ax_grep=( '' '\(,\)' '\|' '\.*[,,,,,,,,,,' ',') ax_find=( '' '\(,\)' '\|' '\.*[,,,,,,+?,,' ',') ax_egrep=( '' '(,)' '|' '\.*[,{,()|+?^$' ',') ax_python=('' '(,)' '|' '\.*[,{,()|+? ' '\') ax_lex=( '' '(,)' '|' '\.*[ { ( |+? ' ' ') ax_perl=( '' '(,)' '|' '\.*[ { ( |+? ' '\') ax_gawk=( '' '(,)' '|' '\.*[,,,(,|+?^$' '\') ax_mawk=( '' '(,)' '|' '\.*[,,,()|+?^$' '\') ax_awk=( '' '(,)' '|' '\.*[ (,|+? ' '\') ax_emacs=( '' '\(,\)' '\|' '\.*[ +? ' ',') ax_lisp=( '' '\\(,\\)' '\\|' '\.*[ +? ' ',') ax_tcl=( '' '(,)' '|' '\.*[ ( |+? ' ',') ax_expect=('' '(,)' '|' '\.*[ ( |+? ' ' ') ax_vi=( '' '\(,\)' '!!' '\.*[ ' ' ') #194# emacs: a backslash ... it is completely unspecial #189# tcl: withing a class, a backslash is completely unspecial # screen size/positioning issues x_regexp=1 ; y_regexp=3 x_hist=3 ; y_hist=$((y_regexp+${#progs[*]}+1)) x_prompt=3 ; y_prompt=$((y_regexp+${#progs[*]}+2)) x_menu=3 ; y_menu=$((y_prompt+2)) x_prompt2=15 y_max=$((y_menu+${#S1_txt[*]})) screensize=`stty size` [ "${screensize% *}" -lt "$y_max" ] && { echo -e " sua tela tem ${screensize% *} linhas e deve ter no mínimo $y_max para que este programa caiba nela. aumente o número de linhas ou retire alguns programas da variável \$progs\n" ; exit 1 } _eol=`echo -ne "\033[0K"` # clear trash until EOL # the cool functions gotoxy(){ echo -ne "\033[$2;$1H" ;} ClearEnd(){ echo -ne "\033[0J"; } ColorOnOff(){ if [ "$cN" ] then unset cN cR cY cW else cN=`echo -ne "\033[m"` # normal cR=`echo -ne "\033[1;31m"` # red cY=`echo -ne "\033[1;33m"` # yellow cW=`echo -ne "\033[1;37m"` # white fi } DoMenu(){ eval Menui=(\"\${$1[@]}\"); menu_n=$((${#Menui[*]}-1)) # ini gotoxy $x_hist $y_hist ; echo " .oO($REPLIES)$_eol" # history gotoxy $x_menu $y_menu ; echo "$cY${Menui[0]}:$cN$_eol" # title for i in `seq $menu_n` # itens do echo " $cW$i$cN) ${Menui[$i]}$_eol"; i=$((i+1)); done ClearEnd # prompt gotoxy $x_prompt $y_prompt ; echo -ne "$cR[1-$menu_n]:$cN $_eol" read -n 1 } Menu(){ DoMenu "$1" case "$REPLY" in [1-9])if [ "$REPLY" -gt "$menu_n" ] then Menu "$1" ; else REPLIES="$REPLIES$REPLY"; fi;; [qQ])STATUS=3 ;; [rR])STATUS=0 ;; [cC])ColorOnOff; Menu "$1";; *)Menu "$1";; esac [ "${STATUS/[03]/}" ] || continue # 0,3: escape status } GetChar(){ gotoxy $x_prompt2 $y_prompt echo -ne "${cR}qual?$cN " ; read -n 1 -r USERINPUT ; uin="$USERINPUT" F_ESCCHAR=1 } #TODO 1st of all, take out repeated chars GetCharList(){ gotoxy $x_prompt2 $y_prompt echo -ne "${cR}quais?$cN " ; read -r USERINPUT ; uin="$USERINPUT" # putting not special chars in not special places: [][^-] [ "${uin/^//}" != "$uin" ] && uin="${uin/^/}^" [ "${uin/-//}" != "$uin" ] && uin="${uin/-/}-" [ "${uin/[//}" != "$uin" ] && uin="[${uin/[/}" [ "${uin/]//}" != "$uin" ] && uin="]${uin/]/}" [ "$1" ] && uin="^$uin" # if any $1, negated list uin="[$uin]" F_ESCCHARLIST=1 } GetString(){ gotoxy $x_prompt2 $y_prompt echo -ne "${cR}txt:$cN " ; read -r USERINPUT ; uin="$USERINPUT" F_ESCCHAR=1 } GetNumber(){ gotoxy $x_prompt2 $y_prompt echo -ne "${cR}N=$cN$_eol" ; read USERINPUT uin="${USERINPUT//[^0-9]/}" # extracting !numbers [ "${uin/666/}" ] || { gotoxy 35 1 ; echo "$cR]:|$cN" ; } # ee [ "$uin" ] || GetNumber # there _must_ be a number } EscChar(){ # escape userinput chars as .,*,[ and friends local c x x2 z i ui esc esc='\'; [ "$1" == 'lisp' ] && esc='\\' # double escape for lisp ui="$uin" eval x=\"\${ax_$1[3]}\" ; x="${x//[, ]/}" # list of escapable chars [ "${ui/[\\\\$x]/}" != "$ui" ] && { # test for speed up for i in `seq 0 $((${#ui}-1))` # for each user char do c="${ui:$i:1}" case "$c" in # special bash chars [?*#%])x2="${x/[$c]/}";; [/}])x2="${x/\\$c/}";; [\\])x2="${x/$c$c/}";; *)x2="${x/$c/}" ;; esac [ "$x2" != "$x" ] && c="$esc$c" # escaping z="$z$c" done uin="$z" # ah, the escaped string } } EscCharList(){ local x esc='\' ; eval x=\"\${ax_$1[4]}\" [ "$x" == '\' ] && uin="${uin/\\\\/$esc$esc}" # escaping escape } Reset(){ gotoxy $x_regexp $y_regexp unset REPLIES HUMAN Regexp[*] for p in ${progs[*]}; do printf " RegExp %-6s: $_eol\n" "$p"; done } ShowRegExp(){ gotoxy $x_regexp $y_regexp local i save="$uin" for i in `seq 0 $((${#progs[*]}-1))` # for each program do [ "$F_ESCCHAR" == '1' ] && EscChar ${progs[$i]} [ "$F_ESCCHARLIST" == '1' ] && EscCharList ${progs[$i]} case "$1" in # check status S2) eval Regexp[$i]="\${Regexp[$i]}\${S2_${progs[$i]}[$REPLY]/@/$uin}";; S0) Regexp[$i]="${Regexp[$i]}${S0_re[$REPLY]}";; S1) Regexp[$i]="${Regexp[$i]}${uin:-${S1_re[$REPLY]}}";; S12) Regexp[$i]="${Regexp[$i]}$TMP_RE";; esac printf " RegExp %-6s: %s\n" "${progs[$i]}" "${Regexp[$i]}" uin="$save" done unset uin USERINPUT F_ESCCHAR F_ESCCHARLIST } clear ColorOnOff echo 'Q)uit R)eset C)olor On/Off __: unknown !!: not supported' while : ; do case ${STATUS:=0} in 0) Reset STATUS=1 Menu S0_txt HUMAN="$S0_txt $cW${S0_txt[$REPLY]}$cN" ShowRegExp S0 STATUS=1 ;; 1) Menu S1_txt TMP_RE="${S1_re[$REPLY]}" HUMAN="$HUMAN, $S1_txt $cW${S1_txt[$REPLY]}$cN" [ "$REPLY" -eq 2 ] && STATUS=12 && continue [ "$REPLY" -eq 3 ] && STATUS=12 && continue [ "$REPLY" -eq 5 ] && GetChar [ "$REPLY" -eq 6 ] && GetCharList [ "$REPLY" -eq 7 ] && GetCharList negated STATUS=2 [ "$REPLY" -eq 8 ] && GetString && STATUS=1 [ "$REPLY" -eq 9 ] && STATUS=1 ShowRegExp S1 ;; 12) Menu S12_txt TMP_RE="[$TMP_RE${S12_re[$REPLY]}]" ShowRegExp S12 STATUS=2 ;; 2) Menu S2_txt [ "$REPLY" -ge 5 ] && GetNumber HUMAN="$HUMAN, $cW${S2_txt[$REPLY]}$cN vez(es)" ShowRegExp S2 STATUS=1 ;; 3) echo -ne "\033[0G" ; ClearEnd echo -e "\n ${HUMAN:-no RegExp}.\n" exit 0 ;; *) echo "Error: STATUS = $STATUS" exit 1 ;; esac done