Expressões regulares no Mediation PDF Imprimir E-mail
Artigos - VoIP e UC
Escrito por Fernando Mercês   
Qua, 02 de Setembro de 2009 11:42

As regras de normalização e rotas criadas para uso com o Mediation Server, do OCS, são baseadas em expressões regulares, um conjunto de regras que provê flexibilidade no tratamento de strings de texto no mundo da computação. Especificamente para o OCS, utilizamos normalmente dígitos, mas o uso expressões regulares, também conhecidas como regex, regexp ou ER, é grande em diversas outras tarefas. Um bom exemplo é o programa grep (global regular expressions print), que foi originalmente escrito para Unix e cria poderosos filtros de texto baseados em regex. Vamos falar um pouco sobre o uso das regex para o Mediation Server, do OCS 2007 R2.

 

 


Introdução

Imagine um caso em que você precisa buscar um arquivo, em meio a milhares deles. O nome do arquivo é, por exemplo, unified2009.txt. Uma busca muito simples permite que você digite apenas texto para buscar. Se você sabe o nome completo do arquivo não há problemas, mas imagine que você só lembre que existe um "2009" no nome dele. Em buscas simples, você vai ter que digitar "2009" e aguardar os resultados (o que pode demorar porque podem haver muitos arquivos com este pedaço de texto no nome, seja no início, no meio ou no fim, a busca vai mostrar todos eles se assim estiver configurada).

Num segundo caso, uma busca um pouco mais refinada permite o uso de metacaracteres, como o asterisco (*), que significa "qualquer coisa". Assim, se você lembra que o "2009" do nome do arquivo vem no final, você pode buscar por "*2009". Já refina mais a busca do que no primeiro caso.

Para buscas ainda mais refinadas alguns poucos metacaracteres não são suficientes. Imagine que você não lembra o número que está no nome do arquivo, você só sabe que há letras e depois quatro dígitos (um ano qualquer). Como faria? É para suprir essas e outras necessidades refinadas que a regex existe. Com regex podemos usar metacaracteres especiais, assim:

*\d{4}\.txt



O asterisco (*) significa "qualquer caractere, em qualquer quantidade". O "\d" diz que o próximo caractere é um dígito (0 até 9) e o "{4}" controla o número de vezes que este caractere se repete. A contra-barra (\) faz com que o próximo caractere seja ignorado pelo interpretador de regex. Neste caso ela é necessária porque o ponto (.) é um metacaractere que tem um significado em regex. Já que queremos que o ponto seja interpretado somente como um ponto comum, usamos a contra-barra antes dele.


Metacaracteres

São caracteres especiais, que significam alguma coisa, bem mais do que sua sumples representação. Já vimos o asterisco (*) e a contra-barra (\) mas há muitos outros. Segue uma lista útil para uso no Mediation:

^ - Representa início. Por exemplo, a expressão ^u (sem aspas) casará com todosos nomes que obrigatoriamente começam com a letra "u".

[...] - Cria uma lista, usada para casar mais de um caractere. Por exemplo, ^[25], casará com qualquer número que comece com 2 ou 5.

[..-..] - Também é uma lista, mas agora com intervalos, ou seja, 33[1-6] casará com números que comecem com 33 e sejam seguidos de um dos dígitos de 1 a 6.

[^...] - Esta é uma lista negada. [^0] casa com qualquer número que não seja zero.

? - O metaractere opcional. Quando usado antes de um outro caractere, diz que este último é opcional no casamento. Por exemplo, ?902 casa com 902 e com 02, porque o 9 é opcional.

{n} - Este é um controle fixo, usado para indicar quantas vezes o caractere anterior se repete. Por exemplo, 9{3} casará com 999.

| - O ou lógico. Serve para representar o ou entre sentenças. Por exemplo, ^(8*|3{2}) casa com número que comecem com 8 ou com 33.

$ - Representa o fim de uma sentença. Deve sempre ser usado. A expressão do exemplo anterior ficaria ^(8*|3{2})$. Novamente, use sempre.

\d - Representa dígitos. ^(\d{10})$ casa com números de 10 dígitos. Uma expressão equivalente é ^([0-9]{10})$. Certo?

Estes são alguns poucos metacaracteres existentes na regex, mas são suficientes para a maioria das regras usadas no Mediation do OCS.


Regras de normalização

No Mediation, precisamos especificar regras para conversão dos números a serem discados para o formato E.164 (RFC) incluindo o caractere "+" no início. Assim, uma chamada interna numa empresa carioca que tenha os ramais internos com 4 dígitos, de 3500 até 3599 e com prefixo público de 2477 poderia ser assim:

Pattern: ^35(\d{2})$

Translation: +5521247735$1

Falamos na regra acima que qualquer número iniciado com 35 e seguido de dois dígitos terá esses dois últimos dígitos prefixados por +5521247735. Ou seja, se o usuário discar 3576, este número será traduzido para +552124773576 e só então será discado. Perceba que os parênteses definem os dígitos que vão para a tradução. Dessa forma, se colocarmos o 35 dentro do parênteses, teremos de removê-lo da expressão de tradução. Ficaria assim:

Pattern: ^(35\d{2})$

Translation: +55212477$1

E o efeito é o mesmo. Perceba na implementação do exemplo que ao digitar um número que case com nossa normalização, ela acontece e só depois o usuário disca:

 

Normalização em funcionamento

 

Agora que sabemos o básico de ER, vamos exercitar seu uso no Mediation a fim de converter os números digitados pelo usuário para o formato E.164 completo e precedido do sinal de adição (+). O conhecimento de ER é essencial para criar regras otimizadas e inteligentes, que evitem problemas na discagem. Além disso, quando falamos do recurso "quick dial" para os telefones IP (LG Nortel, Polycom CX700, etc) precisamos conhecer bem as expressões, do contrário este recurso que normalmente facilita a vida de quem disca pode ser tornar uma tremenda dor de cabeça.

Tomemos como exemplo a cidade do Rio de Janeiro (código 21) e nosso código de país 55. O prefixo de nossa empresa fictícia é 2477 e os ramais são de 4 dígitos, indo de 3500 a 3599, assim como no post da parte 1.

Precisamos criar regras de normalização para tratar os tipos de chamada abaixo:

  • Interna.
  • Emergência.
  • Telefonista/Recepção.
  • Local.
  • DDD.
  • DDI.
  • Gratuita.

Vamos começar analistando o primeiro caso:

 

Chamadas internas (ramal para ramal)

Neste caso temos que prever as ligações de 3500 até 3599. Para isso utilizaremos a regra abaixo:

Pattern: ^(35\d{2})$

Translation: +55212477$

Essa regra permite que números iniciados (^) por 35 seguidos de dois ({2}) dígitos (\d) qualquer sejam traduzidos para o formato E.164.

 

Emergência

Aqui temos que prever as ligações para 190 (Polícia Militar), 192 (Ambulância), 193 (Bombeiros), 194 (Polícia Federal) e 199 (Defesa Civil).

Pattern: ^(19[02349])$

Translation: +55$1

Como estes números são para todo o Brasil, usamos somente o prefixo +55. Lembrando que teremos de tratar isso no media gateway utilizado.

 

Telefonista/Recepção

No Brasil, usualmente discamos 9 para chamarmos a telefonista. Admitindo que o ramal da telefonista seja 3509, vamos à regra:

Pattern: ^9$

Translation: +552124773509

Perceba que neste caso não há uso da variável $1 porque o 9 não precisa sofrer tradução. Alternativamente poderíamos usar:

Pattern: ^(9)$

Translation: +55212477350$1

O resultado é o mesmo, mas no segundo caso usamos a variável $1. Não se deve usar uma variável se o valor dela for sempre constante. Além disso, neste segundo caso, escrevemos um pouco mais. Portanto, prefira o primeiro. Quanto mais simples sua expressão, melhor.

 

Local

Aqui é bom que saibamos todos os prefixos da cidade. No nosso caso (Rio de Janeiro) os prefixos são vários, mas todos começam com os números 2 ou 3 para telefones fixos e de 7 a 9 para celulares. Além disso, todos têm 8 dígitos de comprimento.

Pattern: ^([23789]\d{7})$

Translation: +5521$1

Em outras palavras, números que iniciem por 2, 3, 7, 8 ou 9 seguidos de mais 7 dígitos (o que totaliza 8) são convertidos para o formado E.164.

 

DDD

Aqui a abrangência aumenta. Os códigos de cidade são muitos e não vale a pena tratar todos (você pode consultar uma lista de códigos nacionais e internacionais aqui). Algumas regras são cabíveis como a que não existe código DDD que contenha 0, nem números locais que comecem com 0 ou 1. O comprimento deve ser de 10 dígitos (2 para o código e mais 8 para o número local). Então vamos criar uma regra geral:

Pattern: ^([1-9]{2}[2-9]\d{7})$

Translation: +55$1

Dizemos que os dois primeiros dígitos devem ser de 1 a 9 (para excluir o 0). Em seguida dizemos que o próximo dígito deve ser 2 a 9 (para excluir 0 e 1 do início de um número local) e por fim, seguem mais 7 dígitos quaisquer.

 

DDI

Esta é uma regra mais abrangente ainda. Existem códigos de países com 1, 2 e 3 dígitos, mas não pode haver 0 no início. Além disso, existem códigos de cidades estrangeiras que seguem a mesma regra. É difícil criar uma regra 100% compatível com todas as cidades do mundo, por isso sempre opto por criar uma regra para DDI que exija que o símbolo "+" seja discado. Como conseqüência você ainda permite que o usuário disque o número DDI como vê, ou seja, precedido de "+".

Pattern: ^(\+[1-9]\d{6,13})$

Translation: $1

Para usar esta regra o usuário tem que digitar +, depois qualquer número que não seja 0 e em seguida de 6 a 13 dígitos. Este comprimento variável é dado pelos caracteres de controle {6,13}. Eu o usei porque o comprimento varia a cada cidade/país que será chamado, dentro desta faixa.

 

Gratuitas

Neste tipo de chamada o número discado começa com 0800 e, segundo a resolução nº 86 da ANATEL, deve conter 11 dígitos ao todo.

Pattern: ^(0800\d{7})$

Translation: +55$1

Apesar da resolução da ANATEL estar em vigor desde o ano passado, podem existir ainda telefones 0800 com 10 dígitos. Neste caso, use um intervalo no controle: \d{6,7}.

 

É importante citar que as regras acima são apenas de exemplo e, apesar de funcionarem num ambiente de produção, é recomendável que você crie suas próprias regras para cada caso. Eu tomei como exemplo a cidade brasileira do Rio de Janeiro, por isso use as regras acima somente como base para desenvolver as suas.

 

Para finalizar, seguem algumas dicas importantes na hora de escrever regex para normalização:

  • Evite a lista negada. Prefira dizer qual intervalo é válido ao invés de dizer o que não é válido.
  • Seja direto e simples. Não crie uma expressão impossível de ler, não há necessidade disso no Mediation.
  • Seja claro no nome da regra e escreva sua função no campo "Comments", para facilitar a compreensão futura.
  • Teste demasiadamente a regra antes de colocá-la em produção. O Enterprise Voice Helper ajuda muito neste ponto.
  • Pratique bastante, crie regras fictícias para as mais variadas situações, só assim você poderá ter um conceito forte de regex e conseguirá criar regras sem esfoço e sem consultar nada quando for preciso.

Boas regras!