HashCode

An organizer of symbols

Archive for the ‘RegExps’ Category

Utilitário de Expressões Regulares

Thursday, April 12th, 2007

Tenho uma função em PL/pgSQL que identifica a operadora pelo número e DDD denominada ‘operadora’

CREATE OR REPLACE FUNCTION operadora(text) RETURNS text AS '
declare
  ops text[]:= array['VIVO','CLARO', 'TIM','OI','Amazônia','Telemig','BRT','CTBC','Sercomtel','Nextel'];
  regexps text[]=array[
  '((2[1-9]95|1[1-9](95|7[1-4]))|[49][1-9]9[1-4]|([25-7][1-9]9[6-9]|1[1-9]9[6-8]))[0-9]{6}$',
  '([12568][1-9]9[1-4]|4[1-9]88|[37][1-9]8[124]|6195|1[1-9](76|89))[0-9]{6}$',
  '(((([48][1-9]9[6-9])|([37][1-9]9[1-4])|(1[1-9]8[1-5]|[56][1-9]81)|([29][1-9]8[1-3])|(4381[0-9])|(1[1-9]86))[0-9]{6})|5[1-5]99(11|13|39|8[1-9])[0-9]{4})$',
  '[237-9][1-9]8[6-8][0-9]{6}$',
  '9[1-9]9[6-9][0-9]{6}$',
  '3[1-8]9[6-9][0-9]{6}$',
  '[4-6][1-9]84[0-9]{6}$',
  '((3[1-8](96[0-9]{6}|99[67][0-9]{5}|999[1-9][0-9]{4}))|(1[1-9]99[0-9]{6}))$',
  '4[1-6]99(4[1-6]|9[1-8])[0-9]{4}$',
  '7[0-9]{7}$'
];
begin
  for i in 1..10 loop
    if $1 ~ regexps[i] then --se match retorna a posiç
	return ops[i];
    end if;
  end loop;
    return 'outros';
end
' LANGUAGE 'plpgsql' VOLATILE;

Isso funciona da seguinte forma, para cada operadora em ops temos uma expressão regular em regexps e um loop que faz match para todas as regexps.

Exemplo, a fração que analisa a operadora VIVO no centro oeste esta na regexps[0] em negrito(ou morenito, como estão dizendo isso por ai!)

….([25-7][1-9]9[6-9]|1[1-9]9[6-8]))[0-9]{6}$

As regras para determinar as operadoras são:

Trunking com a Nextel utiliza a série começada com 7. A Vivo em São Paulo está também utilizando a série 7 (71 a 74). A série 95 está sendo utilizada pela Vivo em São Paulo e Rio de Janeiro e pela Claro no Distrito Federal. (Marcado com * na tabela a seguir)

Operadora por área e Banda

Estado (DDD)

Banda A

(96 a 99)

Banda B

(91 a 94)

Banda D

(8)

Banda E

(8)

RJ, ES

(21 a 28)

Vivo
Claro

Oi

86 a 88

TIM

81 a 83

Amazônia

(91 a 99)

Amazônia Celular
Vivo

MG

(31 a 38)

Telemig Celular
TIM

Claro

84

BA, SE

(71 a 79)

Vivo
TIM

Claro

81

Nordeste

(81 a 89)

TIM
Claro

-

PR, SC

(41 a 49)

TIM
Vivo

Claro

88

Brasil Telecom

84

RS

(51 a 55)

Vivo
Claro

TIM

81

Centro Oeste

(61 a 69)

SP (11 a 19)

Vivo*
Claro*

TIM

81-85

 

-

Casos Especiais de Operadoras (sempre tem :)

Operadora

Cidades
CTBC Celular

Minas Gerais (96, 9960-9979 e 9991-9999)

São Paulo(99)

Sercomtel Cel.

Londrina e Tamarana, PR (9941-9946 e 9991-9998)

TIM

Pelotas e região RGS.

(9911, 9913, 9939, 9981-9989)

Londrina e Tamarana, PR, área 43 (81)

São Paulo (86)

Claro

São Paulo (76 e 89)

Vivo

São Paulo (71, 72, 73 e 74)

Para facilitar o desenvolvimento das expressões, reduzi cada regra de cada localidade de cada operadora em ‘mini-expressões’, assim:

2[1-9]95
1[1-9](95|7[1-4])
[49][1-9]9[1-4]
[25-7][1-9]9[6-9]
1[1-9]9[6-8]
....

Depois juntei tudo colocando um ou entre cada mini-expressão.

Funcionar funciona… mas como sempre teremos novas exceções. Um dos casos seria a utilização de Trunking ou banda de outra operadora ou uma norma da Anatel. Portanto se uma operadora faz parceria/pacto/etc com outra operadora teremos que alterar a expressão relativa a operadora, uma tarefa não muito agradável como essa da expressão da TIM.

(((([48][1-9]9[6-9])|([37][1-9]9[1-4])|(1[1-9]8[1-5]|[56][1-9]81)|([29][1-9]8[1-3])|(4381[0-9])|(1[1-9]86))[0-9]{6})|5[1-5]99(11|13|39|8[1-9])[0-9]{4})$

Dividir novamente e depois juntar tudo … em uma masturbação codificante!? … era isso que eu fazia :|.

Como sofremos por falta de informações ou preguiça de pesquisar!

Pesquisando(com preguiça de quebrar a expressão) encontrei o kregexpeditor, que eu ignorava por começar com K de KDE, que ao longo do tempo-linux esta acabando com o meu preconceito KDE/Qt.

Dei um apt-get e instalei o cara.

Puts! Tenho agora um editor gráfico de expressoes regulares!
Posso trocar isso

(((([48][1-9]9[6-9])|([37][1-9]9[1-4])|(1[1-9]8[1-5]|[56][1-9]81)|([29][1-9]8[1-3])|(4381[0-9])|(1[1-9]86))[0-9]{6})|5[1-5]99(11|13|39|8[1-9])[0-9]{4})$

por algo mais amigável como

regexp.png

Com o kregexpeditor vc pode abrir um arquivo texto pra fazer o match , criar e alterar expressões regulares em texto ou no modo gráfico.

Gostei muito do editor, tenho que rever meus conceitos sobre K*

String e Regexp com caracteres acentuados (pt-BR)

Saturday, March 10th, 2007

Trabalhando com ruby observei que os métodos de upcase e dowmcase da class String ignoram os acentos da nossa língua.
Transformando uma oração do tipo “João fez círculos e um Ângulo sem vétice?!”, em letras maisculas o resultado do método upcase é “JOãO FEZ CíRCULOS E UM ÂNGULO SEM VéRTICE?!”.
Vejam que os nossos queridos caracteres acentuados não foram modificados. Para solucionar o problema, em primeiro momento, criei os métodos br_upcase e br_downcase
no módulo BrazilianString e fiz um mixi na classe String, portanto para oração acima os resultados são:

- “João fez círculos e um Ângulo sem vértice?!”.br_upcase => “JOÃO FEZ CÍRCULOS E UM ÂNGULO SEM VÉRTICE?”

- “João fez círculos e um Ângulo sem vértice?!”.br_downcase => “joão fez círculos e um ângulo sem vértice?”

e um método auxiliar para retirar os acentos

- “João fez círculos e um Ângulo sem vértice?!”.desacentualize => “Joao fez circulos e um Angulo sem vertice?”

Algo semelhante acontece com expressões regulares, mas isso não é uma peculiaridade de Ruby mas de outras linguagens também.
Nas expressões regulares temos as abreviações

<b>Sequence  As [ ... ]        Meaning </b>
&#92;d      [0-9] 	          Digit character(Digito)
&#92;D 	[^0-9] 	          Nondigit(Não dígito)
&#92;s 	[&#92;s&#92;t&#92;r&#92;n&#92;f]    Whitespace character(caracteres considerados em branco)
&#92;S 	[^&#92;s&#92;t&#92;r&#92;n&#92;f]   Nonwhitespace character(caracteres não considerados em branco)
&#92;w 	[A-Za-z0-9_] 	  Word character A(caracter de palava)
&#92;W 	[^A-Za-z0-9_]   Nonword character(não seja caracter de palava)


Vamos testar alguns caracteres acentuados nas expressões regulares:

Quatro carateres de palavra

"João" =~ /&#92;w{4}/        => nil

sem o til

"Joao" =~ /&#92;w{4}/        => 0

Ahhh! Saquei! - Então as expressões regulares não detectam os nosso caracteres acentuados. É, as Regexp detestam os caracteres :)
As regexps não consideram nossos acentos no hiato dos ‘Word character’.

Fiz um esqueminha. Adicionei a classe String o método br_match responsável por fazer match e nas listas e as abreviações \w e \W modificadas.

Source    Para
&#92;w       &#92;wãàáâäèéêëìíîïõòóôöùúûüçÃÀÁÂÄÈÉÊËÌÍÎÏÖÒÓÔÙÚÛÜÇ
&#92;W       [^&#92;wãàáâäèéêëìíîïõòóôöùúûüçÃÀÁÂÄÈÉÊËÌÍÎÏÖÒÓÔÙÚÛÜÇ]
a-z      a-zãàáâäèéêëìíîïõòóôöùúûüç
A-Z      A-ZÃÀÁÂÄÈÉÊËÌÍÎÏÖÒÓÔÙÚÛÜÇ

Utilizando assim

"João".br_match /&#92;w{4}/        => 0

Quebra um galho
A classe e o módulo estão aqui.