:TITLE: Mais Expressões Regulares 102
;#
;# RCSID: $Header: /home/clif/CVS_ROOT/TclTutor/Tcl21.lsn,v 1.6 2000/04/24 16:17:51 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# Veja o arquivo "AVISO" com os termos da licença.
;#
;#*********************************************************
;# Portuguese translation: Lucio Agostinho Rocha
;# E-mail: outrosdiasvirao@yahoo.com.br
;# Last update: 05/01/2006
;#*********************************************************
:LESSON_TEXT_START_LEVEL 0:
A expressão regular (<I>exp</I>) nos dois comandos de tratamento da
espressão regular é avaliada pelo tratador Tcl durante a fase de substituição Tcl.
Isso pode fornecer muito poder, e também requerer muito cuidado.
<P>
Esses exemplos mostram alguns dos truques da avaliação de expressões
regulares. Os campos em cada exemplo são discutidos em detalhes
cuidadosos no nível iniciante.
<DL>
<B><DT>regexp</B> <I>?modificadores? exp string ?varBusca? ?varSubBusca1... varSubBuscaN?</I>
<DD>Pesquisa na <I>string</I> pela expressão regular <I>exp</I>.  Se um
parâmetro <I>varBusca</I> é fornecido, então a substring que é compatível com a
expressão regular é copiada para <I>varBusca</I>. Se
as variáveis <I>varSubBuscaN</I> existem, então as partes entre parênteses
da pesquisa na string são copiadas para as variáveis <I>varSubBusca</I>, 
trabalhando da esquerda para a direitra.
<B><DT>regsub</B> <I>?modificadores? exp string varSubstituição nomeVar</I>
<DD>Pesquisa na <I>string</I> por substrings que sejam compatíveis com
a expressão <I>exp</I> e as substitui com <I>varSubstituição</I>. A string
resultante é copiada para <I>nomeVar</I>.
</DL>
:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
<DL>
<B><DT>regexp</B> <I>?modificadores? exp string ?varBusca? ?varSubBusca1... varSubBuscaN?</I>
<DD>Pesquisa na <I>string</I> pela expressão regular <I>exp</I>.  Se um
parâmetro <I>varBusca</I> é fornecido, então a substring que é compatível com a
expressão regular é copiada para <I>varBusca</I>. Se
as variáveis <I>varSubBuscaN</I> existem, então as partes entre parênteses
da pesquisa na string são copiadas para as variáveis <I>varSubBusca</I>, 
trabalhando da esquerda para a direitra.
<B><DT>regsub</B> <I>?modificadores? exp string varSubstituição nomeVar</I>
<DD>Pesquisa na <I>string</I> por substrings que sejam compatíveis com
a expressão <I>exp</I> e as substitui com <I>varSubstituição</I>. A string
resultante é copiada para <I>nomeVar</I>.
</DL>
<P>
A expressão regular (<I>exp</I>) nos dois comandos de tratamento da
expressão regular é avaliada pelo tratador Tcl durante a fase de substituição Tcl.
Isso pode fornecer muito poder, e também requerer muito cuidado.
<P>
Esses exemplos mostram alguns dos truques da avaliação de expressões
regulares. Os campos em cada exemplo são discutidos em detalhes
cuidadosos no nível iniciante.
<P>
Os pontos a serem lembrados quando você ler os exemplos são:
<UL>
<LI> Um colchete esquerdo tem significado para a fase de substituição,
e para o tratador da expressão regular.
<LI> Um conjunto de parênteses, um sinal de mais, e um asterisco têm
significado para o tratador da expressão regular, mas não para a
fase de substituição Tcl.
<LI> Uma seqüência de barra invertida (\n, \t, etc) tem significado para a
fase de substituição Tcl, mas não para o tratador da expressão regular.
<LI> Um caracter precedido por barra invertida (\[) tem significado para
a fase de substituição Tcl e para o tratador da expressão regular.
</UL>
<P>
A fase na qual um caracter tem significado afeta quantas
barras invertidas são necessárias para encontrar o caracter que você
deseja encontrar. Um barra invertida pode ou delimitar a frase em
chaves, ou colocar uma barra invertida antes do caracter precedido
por ela.
<P>
Para passar um colchete esquerdo para o tratador da expressão regular
avaliar como um intervalo de caracteres, utilize uma barra invertida.
Para ter um colchete esquerdo para o tratador da expressão regular,
utilize 2 barras invertidas (uma para desativar o colchete na fase
de substituição Tcl, e outra para desativar o colchete para o tratador
da expressão regular). Se você tiver a string colocada dentro de aspas
duplas, então uma barra invertida que você quiser passar para o
tratador da expressão regular deve também ser precedida por uma
barra invertida.
<P>
Se você ainda não apertou o botão <B>Executar exemplo</B> faça isso
agora, e examine a saída. Se alguma coisa no código ou na saída não
for óbvia, o próximo nível de experiência irá detalhar cuidadosamente
cada campo dos exemplos.
:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
Se você não apertou o botão <B>Executar exemplo</B>, faça isso agora
e observe a saída enquanto você lê o restante dessa lição.
<P>
O argumento <B>exp</B> para <CODE>regexp</CODE> ou <CODE>regsub</CODE> é
processado pelo passo de substituição Tcl. Isso afeta o mecanisno de
como expressões regulares podem ser formadas. Se a expressão regular não
tem seqüências de barra invertida que você deseja ter convertidas pela
fase de substituição Tcl, então o argumento <B>exp</B> pode ser delimitado
por chaves. Se você deseja que quaisquer substituições ocorram
o argumento <B>exp</B> deve ser delimitado por aspas duplas. Neste caso,
caracteres que têm significado para a fase substituição Tcl devem ser
precedidos com uma barra invertida.
<P>
<H4>Exemplo 1</H4>
No primeiro exemplo, a expressão regular é colocada dentro de chaves.
Isso poderia ser feito neste caso porque não houve seqüências de
barra invertida para serem expandidas pela fase de substituição. A
primeira seqüência de expressão regular (<CODE>[^ ]*</CODE>) irá
encontrar qualquer número de qualquer caracter, exceto um espaço.
No texto do exemplo, esta é a porção <CODE>/dev/wd0*</CODE>
de cada linha.
<P>
A segunda seqüência (<CODE> *</CODE>) encontra qualquer número de
espaços. Neste caso, os espaços entre o dispositivo e o
primeiro conjunto de números.
<P>
A terceira seqüência (<CODE>([0-9]+)</CODE>) irá encontrar qualquer 
quantidade de qualquer dígito. Isso encontra o primeiro número em
cada linha. Os parênteses em torno dessa seqüência fazem com que
o subconjunto de caracteres na string que é compatível com essa 
seqüência seja copiado para a primeira variável. Neste exemplo,
esta é a variável <I>tamanho</I>.
<P>
A quarta seqüência (<CODE>[^/]*</CODE>) irá encontrar qualquer caracter,
exceto uma barra. Isso encontra os espaços, números e sinais de porcentagem
seguindo para a palavra final de cada linha.
<P>
A quinta seqüência (<CODE>(/[a-z]*)</CODE>) encontra qualquer string de
letras minúsculas precedidas por uma barra. Neste exemplo, encontra os
pontos de montagem dos discos. Como essa seqüência está delimitada por 
parênteses, o subconjunto de caracteres encontrado é copiado para
a segunda variável, neste caso <CODE>montado</CODE>.
<P>
<H4>Exemplo 2</H4>
O segundo exemplo usa seqüências de barra invertida, então tem que
ser delimitado por aspas duplas. Ele também procura caracteres na
string que têm significado especial para o tratador da expressão regular.
Esse é o motivo da seqüência de escape ser tão extensa.
<P>
Não é óbvio, mas há uma tabulação entre o <CODE>?</CODE> e o
<CODE>[32</CODE> neste exemplo.
<P>
Tomando a seqüência da expressão regular em ordem, a primeira expressão
(<CODE>\[^\t]+</CODE>) seleciona qualquer caracter, exceto um caracter de
tabulação. Isso busca tudo na string exceto o caracter de tabulação antes
de <CODE>[32</CODE>. O colchete inicial na expressão regular é precedido
pela barra invertida para permitir que ele seja passado para o tratador da
expressão regular, ao invés de ter na fase de substituição a tentativa de
executar a string entre os colchetes como um comando.
<P>
A segunda seqüência é simplesmente um (<CODE>\t</CODE>), que encontra o
caracter de tabulação.
<P>
A terceira seqüência, (<CODE>\\\[\[0-9]+</CODE>), tem um pequeno truque.
O objetivo é fazer com que o tratador da expressão regular encontre
a porção do número <B>junto ao colchete esquerdo</B> da string ([32). 
Como a fase de substituição irá converter seqüências de barra invertida 
a caracteres únicos, há necessidade de ter três barras invertidas antes
do colchete. As primeiras duas barras irão ser convertidas em uma única
barra pela fase de substituição Tcl, então o conjunto formado pela
barra invertida junto ao colchete esquerdo (\[) será convertido em
um colchete esquerdo apenas. O tratador da expressão regular irá ver
a string <CODE>\[[0-9]+</CODE>, que irá procurar por um colchete
esquerdo seguido por um ou mais dígitos.
<P>
A quarta seqüência é (<CODE>\\\(0x</CODE>, que é convertida pela fase de
substituição Tcl para <CODE>\(0x</CODE>, que irá encontrar um parêntese
esquerdo, zero e 'x'.
<P>
A próxima seqüência <CODE>(\[0-9a-fA-F]+)</CODE> é quase trivial nesse ponto.
Ela busca por uma quantidade desconhecida de dígitos hexadecimais, mas pelo
menos um dígito. A seqüência de caracteres que são compatíveis com essa
seqüência serão colocados na variável <I>valorHex</I>.
<P>
A próxima seqüência é o <CODE>\\\)</CODE> que é convertida para <CODE>\)</CODE>.
Ela busca por um parêntese direito. O código do tratador da expressão regular
conta os parênteses direitos e esquerdos que não são precedidos por barra
invertida, e irá reclamar se a contagem de um não for igual à do outro.
<P>
A seqüência final é apenas um colchete direito, que busca por um
colchete esquerdo. Isso poderia ser escrito também como
<CODE>\\\[</CODE>, mas o tratador da expressão regular não conta
colchetes da forma como ele conta parênteses.
<P>
O terceiro e quarto exemplos mostram como a colocação de ^ afeta o
que é encontrado.
<P>
<H4>Exemplo 3</H4>
No primeiro desses exemplos, a expressão regular <CODE>\[^a-f]*def</CODE> 
encontra qualquer quantidade de quaisquer caracteres, exceto a-f, e então
as letras def.
Isso encontra o <B>^def</B> na string exemplo.
<P>
<H4>Exemplo 4</H4>
A expressão regular no quarto exemplo (<CODE>\[a-f^]*def</CODE>)
tem o ^ movido para o fim da seqüência. Esta seqüência encontra qualquer
quantidade de quaisquer caracteres no intervalo de 'a' a 'f', e o ^ seguido
pelas letras <B>def</B>. Isso encontra toda a string.
<P>
<H4>Exemplo 5</H4>
Os exemplos 5 e 6 mostram <CODE>regsub</CODE> sendo usado para encontrar
um literal ^.
<P>
O exemplo 5 tem uma expressão regular delimitada por chaves. Isso fornece
um nível sem substituição. Então o \^ é a string exata passada para
o tratador da expressão regular. Isso encontra o literal ^.
<P>
<H4>Exemplo 6</H4>
No exemplo 6, a expressão regular é delimitada por aspas duplas, o que
requer mais seqüências de barra invertida de forma a obter a string esperada
para o tratador da expressão regular.
<P>
A primeira seqüência no exemplo é <CODE>(\[a-f]+)</CODE>. O parêntese esquerdo
não é avaliado pela fase de substituição Tcl, e deveria ser avaliado
pelo tratador da expressão regular para agrupamento, então ele não precisa
ser precedido por barra invertida. O colchete esquerdo deveria ser avaliado
pela fase de substituição Tcl como o resultado da execução do comando
dentro dos colchetes. Nós queremos que a frase delimitada por colchetes
seja avaliada pelo tratador da expressão regular, portanto, ela é
precedida com uma única barra invertida.
<P>
A segunda seqüência, <CODE>\\^</CODE>, é precedida por duas barras invertidas
que serão avaliadas pela fase de substituição Tcl, e serão convertidas em
uma única barra invertida. O \^ será passado para o tratador da expressão
regular, que irá buscar o símbolo ^ como um ^ literal, ao
invés de avaliá-lo como um símbolo que 'busca qualquer caracter com
exceção de'.
<P>
A seqüência final, <CODE>(\[a-f]+)</CODE> é a mesma que a primeira, e
a barra invertida é usada pelas mesmas razões.
<P>
Experimente um pouco mudar o agrupamento de aspas duplas para
chaves e volte com o agrupamento anterior para entender a forma
como os caracteres precisam ser precedidos por barra invertida.
:TEXT_END:

:CODE_START:
set lista1 [list {/dev/wd0a        17086    10958     5272    68%    /}\
                 {/dev/wd0f       179824   127798    48428    73%    /news}\
                 {/dev/wd0h      1249244   967818   218962    82%    /usr}\
                 {/dev/wd0g        98190    32836    60444    35%    /var}]

foreach linha $lista1 {
  regexp {[^ ]* *([0-9]+)[^/]*(/[a-z]*)} $linha varBusca tamanho montado
  puts "$montado tem $tamanho blocos"
  }

set linha {Vetor Interrupção?	[32(0x20)]}
regexp "\[^\t]+\t\\\[\[0-9]+\\(0x(\[0-9a-fA-F]+)\\)]" $linha varBusca valorHex
puts "O Hexadecimal padrão é: 0x$valorHex"

set str2 "abc^def"
regexp "\[^a-f]*def" $str2 varBusca
puts "usando \[^a-f] o valor encontrado é: $varBusca"

regexp "\[a-f^]*def" $str2 varBusca
puts "usando \[a-f^] o valor encontrado é: $varBusca"

regsub {\^} $str2 " é seguido por: " str3
puts "$str2 com o ^ substituído é: \"$str3\""

regsub "(\[a-f]+)\\^(\[a-f]+)" $str2 "\\2 seguido de \\1" str3
puts "$str2 é convertido para \"$str3\""

:TEXT_END:

