13. Operações com Strings
A maior parte do trabalho com sistemas comerciais consiste basicamente em processar arquivos, registros e campos. Algumas vezes, porém, é necessário fazer algumas operações com strings, caracter a caracter. O COBOL possui alguns recursos específicos para facilitar a operação com strings.
Substrings
Modificadores de referência são recursos do COBOL que permitem ao programador fazer referências a uma parte de uma variável alfanumérica. Isso também poderia ser feito através da subdivisão da variável em itens elementares, mas os modificadores de referência facilitam esse trabalho.
Veja o exemplo abaixo. A data é uma variável alfanumérica de 10 posições no formato DD/MM/AAAA. Suponha que tenhamos que mover apenas o mês e o ano para um determinado campo. Uma das soluções seria:
01 DATA-X. 03 FILLER PIC X(003). 03 MES-ANO-X PIC X(007). ... MOVE MES-ANO-X TO WR-DET-MES-ANO
Usando modificados de referência podemos mover apenas a parte que nos interessa, sem precisar criar itens elementares só para isso:
01 DATA-X PIC X(010). ... MOVE DATA-X(4:7) TO WR-DET-MES-ANO
O comando acima move apenas a substring que começa na posição 4 e tem tamanho de 7 caracteres. Você poderia usar variáveis – ou uma combinação de variáveis e literais – para indicar a posição inicial e a extensão da substring que pretende acessar. Os três exemplos abaixo são válidos:
MOVE DATA-X(POSINI:TAMSTR) TO WR-DET-MES-ANO MOVE DATA-X(WT-INI:7) TO WR-DET-MES-ANO MOVE DATA-X(4:WT-TAM) TO WR-DET-MES-ANO
A extensão pode ser omitida. O exemplo abaixo moveria para a variável WR-DET-MES-ANO a substring de DATA-X que começa na posição 4 e que vai até o último caracter dessa variável:
MOVE DATA-X(4:) TO WR-DET-MES-ANO
Também é possível aplicar modificadores de referência a ocorrências isoladas de uma tabela interna ou array. O próximo exemplo move apenas os três primeiros caracteres da décima segunda ocorrência da tabela interna WV-MES:
MOVE WV-MES(12) (1:3) TO WR-DET-MES
Concatenando strings
O COBOL permite a concatenação de dois ou mais campos alfanuméricos através do comando STRING. Seu formato mais simples é:
STRING campo1 campo2 ... campoN INTO campoX
Neste formato, todo o conteúdo de campo1, campo2 … campoN é copiado, caracter a caracter, para campoX.
01 CAMPO1 PIC X(010) VALUE “COMMON”.
01 CAMPO2 PIC X(010) VALUE “BUSINESS”.
01 CAMPO3 PIC X(010) VALUE “ORIENTED”.
01 CAMPO4 PIC X(010) VALUE “LANGUAGE”.
01 NOME-COMPLETO PIC X(040) VALUE SPACES.
...
STRING CAMPO1 CAMPO2 CAMPO3 CAMPO4 INTO NOME-COMPLETO
DISPLAY “NOME COMPLETO: “ NOME-COMPLETO
O trecho acima, quando executado, mostrará:
NOME COMPLETO: COMMON BUSINESS ORIENTED LANGUAGE
Os espaços entre as palavras são os espaços que existiam à direita de CAMPO1, CAMPO2, CAMPO3 e CAMPO4 (repare que essas variáveis têm dez caracteres de tamanho). O comando concatenou todos os caracteres (inclusive os espaços em branco) e os juntou na variável NOME-COMPLETO porque assumiu a opção default DELIMITED BY SIZE.
Mas o comando STRING permite que sejam estabelecidos outros delimitadores. Seguindo no mesmo exemplo, se fizéssemos…
STRING CAMPO1 CAMPO2 CAMPO3 CAMPO4
DELIMITED BY SPACE
INTO NOME-COMPLETO
DISPLAY “NOME COMPLETO: “ NOME-COMPLETO
… teríamos a seguinte saída:
NOME COMPLETO: COMMONBUSINESSORIENTEDLANGUAGE
Observe que o caracter que indicamos na cláusula DELIMITED BY marca o fim da string a ser copiada; o delimitador em si não é copiado. Para inserir um espaço depois de cada palavra poderíamos combinar variáveis e literais, cada uma delas com um tipo de delimitador:
STRING CAMPO1 DELIMITED BY SPACE " " DELIMITED BY SIZE CAMPO2 DELIMITED BY SPACE " " DELIMITED BY SIZE CAMPO3 DELIMITED BY SPACE " " DELIMITED BY SIZE CAMPO4 DELIMITED BY SPACE INTO NOME-COMPLETO DISPLAY "NOME COMPLETO: " NOME-COMPLETO
Nesse exemplo o programa exibiria…
NOME COMPLETO: COMMON BUSINES ORIENTED LANGUAGE
…porque as variáveis CAMPO1, CAMPO2, CAMPO3 e CAMPO4 foram concatenadas até o primeiro espaço encontrado, exclusive. Já os literais “ “ (espaço) foram copiados by size.
O comando STRING não apaga o valor do campo de destino antes de iniciar as cópias; ele simplesmente copia o primeiro caracter do primeiro campo para a primeira posição do campo de destino e para de copiar quando chega ao final do campo (DELIMITED BY SIZE) ou encontra o delimitador informado (DELIMITED BY literal). Os caracteres do campo de destino que não receberam conteúdo ficam com seus valores anteriores. Observe o exemplo abaixo:
MOVE ALL “*” TO NOME-COMPLETO
STRING CAMPO1 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO2 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO3 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO4 DELIMITED BY SPACE
INTO NOME-COMPLETO
DISPLAY "NOME COMPLETO: " NOME-COMPLETO
O campo de destino (NOME-COMPLETO) foi previamente preenchido com asteriscos. Quando o comando STRING é executado os campos e literais de origem são copiados caracter a caracter, deixando os demais com o conteúdo anterior. O resultado do DISPLAY seria:
NOME COMPLETO: COMMON BUSINESS ORIENTED LANGUAGE************************
Por default, os caracteres começam a ser copiados para a primeira posição do campo de destino, mas isso pode ser mudado com a cláusula WITH POINTER:
MOVE ALL “*” TO NOME-COMPLETO
MOVE 6 TO PONTEIRO
STRING CAMPO1 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO2 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO3 DELIMITED BY SPACE
" " DELIMITED BY SIZE
CAMPO4 DELIMITED BY SPACE
INTO NOME-COMPLETO
WITH POINTER PONTEIRO
DISPLAY "NOME COMPLETO: " NOME-COMPLETO
Nesse caso, criamos na WORKING uma variável chamada PONTEIRO e iniciamos ela com o valor 6 antes do comando STRING. Ela fará com que o conteúdo concatenado só comece na sexta posição do campo de destino. A saída desse trecho de programa seria:
NOME COMPLETO: *****COMMON BUSINESS ORIENTED LANGUAGE*****************
Separando strings
Quando precisamos separar uma string maior em strings menores, delimitadas por algum caracter ou não, usamos o comando UNSTRING, que em seu formato mais simples pode ser codificado assim:
UNSTRING campo-origem INTO campo1 campo2 ... campoN
Vamos ver como funciona num exemplo prático:
01 ELEMENTOS. 03 ELEMENTO1 PIC X(020) VALUE SPACES. 03 ELEMENTO2 PIC X(020) VALUE SPACES. 03 ELEMENTO3 PIC X(020) VALUE SPACES. 03 ELEMENTO4 PIC X(020) VALUE SPACES. 01 NOME-COMPLETO PIC X(080) VALUE “COMMON BUSINESS ORIENTED LANGUAGE”. ... UNSTRING NOME-COMPLETO INTO ELEMENTO1 ELEMENTO2 ELEMENTO3 ELEMENTO4 DISPLAY “ELEMENTO1: “ ELEMENTO1 DISPLAY “ELEMENTO2: “ ELEMENTO2 DISPLAY “ELEMENTO3: “ ELEMENTO3 DISPLAY “ELEMENTO4: “ ELEMENTO4
Esse trecho de código exibiria as seguintes mensagens na tela do usuário:
ELEMENTO1: COMMON BUSINESS ORIE ELEMENTO2: NTED LANGUAGE ELEMENTO3: ELEMENTO4:
Repare que o programa copiou o campo de origem (NOME-COMPLETO), caracter a caracter, para os campos de destino (ELEMENTO1, ELEMENTO2, ELEMENTO3 e ELEMENTO4). Ele preencheu os 20 bytes do primeiro campo e depois continuou no segundo. Os campos 3 e 4 ficaram com espaços porque não havia mais conteúdo no campo de origem.
Parar separar o campo de origem palavra por palavra precisamos indicar um delimitador. O trecho…
UNSTRING NOME-COMPLETO
DELIMITED BY SPACE
INTO ELEMENTO1 ELEMENTO2 ELEMENTO3 ELEMENTO4
DISPLAY “ELEMENTO1: “ ELEMENTO1
DISPLAY “ELEMENTO2: “ ELEMENTO2
DISPLAY “ELEMENTO3: “ ELEMENTO3
DISPLAY “ELEMENTO4: “ ELEMENTO4
…mostraria:
ELEMENTO1: COMMON ELEMENTO2: BUSINESS ELEMENTO3: ORIENTED ELEMENTO4: LANGUAGE
Assim como no comando STRING, qualquer literal pode ser usada como delimitador no comando UNSTRING:
UNSTRING LINHA-PLANILHA DELIMITED BY “;” INTO CIDADE ESTADO PAIS CEP
Separaria a variável LINHA-PLANILHA…
ITABIRITO;MINAS GERAIS;BRASIL;35450-000
Em…
CIDADE: ITABIRITO ESTADO: MINAS GERAIS PAIS: BRASIL CEP: 35450-000
Agora observe esse outro exemplo, onde a variável LINHA planilha possui mais de um ponto-e-vírgula separando cada campo:
ITABIRITO;;;MINAS GERAIS;;;BRASIL;;;35450-000
Nesse caso, o resultado do UNSTRING seria:
CIDADE: ITABIRITO ESTADO: PAIS: CEP: MINAS GERAIS
Isso aconteceu porque dissemos que nosso delimitador era formado por um único ponto-e-vírgula. O COBOL interpretou que entre o primeiro e o segundo ponto-e-vírgula existia um caracter nulo e por isso preencheu o segundo campo (ESTADO) com esse valor. A mesma coisa aconteceu entre o segundo o segundo e o terceiro ponto-e-vírgula, o que também deixou o campo PAIS vazio.
Para instruir o COBOL a interpretar sucessivas ocorrências de um delimitador como um só precisamos incluir a opção ALL na cláusula DELIMITED BY:
UNSTRING LINHA-PLANILHA
DELIMITED BY ALL “;”
INTO CIDADE ESTADO PAIS CEP
Resultaria em…
CIDADE: ITABIRITO ESTADO: MINAS GERAIS PAIS: BRASIL CEP: 35450-000
Pesquisando substrings
Quando queremos verificar se uma substring aparece no conteúdo de uma variável alfanumérica usamos o comando INSPECT:
INSPECT variável TALLYING contador FOR ALL literal
Esse comando vai contar quantas vezes literal aparece no conteúdo de variável e a quantidade será armazenada na variável numérica contador. O exemplo abaixo conta quantas vezes o caracter arroba aparece no conteúdo da variável WT-NM-EMAIL. O resultado é salvo na variável WT-CT-ARROBA:
INSPECT WT-NM-EMAIL TALLYING WT-CT-ARROBA FOR ALL “@”
O comando INSPECT possui diversas variações. É possível, por exemplo, obter o tamanho efetivamente preenchido em uma variável alfanumérica:
03 NOME PIC X(020) VALUE “PAULO”. 03 CONTADOR PIC 9(006) VALUE ZEROS. ... INSPECT NOME TALLYING CONTADOR FOR CHARACTERS BEFORE SPACE DISPLAY “NOME PREENCHIDO COM “ CONTADOR “ CARACTERES”
O exemplo acima mostraria…
NOME PREENCHIDO COM 5 CARACTERES
…pois instruímos o comando a contar a quantidade de caracteres existentes antes do primeiro espaço. Naturalmente, também é possível contar substrings com mais de um caracter:
03 NOME-COMPLETO PIC X(040) VALUE “JOHN SMITH”. 03 SOBRENOME PIC X(005) VALUE “SMITH”. 03 CONTADOR PIC 9(006) VALUE ZEROS. ... INSPECT NOME-COMPLETO TALLYING CONTADOR FOR ALL SOBRENOME DISPLAY “O SOBRENOME APARECE “ CONTADOR “VEZ(ES)”
Esse exemplo acima mostraria:
O SOBRENOME APARECE 1 VEZ(ES)
O comando INSPECT também permite contar mais de uma substring ao mesmo tempo usando mais de um contador. O exemplo abaixo conta quantas vezes cada vogal aparece numa variável alfanumérica:
INSPECT variável TALLYING contadorA FOR ALL “A” contadorE FOR ALL “E” contadorI FOR ALL “I” contadorO FOR ALL “O” contadorU FOR ALL “U”
Podemos também contar várias substrings usando um único contador:
INSPECT variável TALLYING contador FOR ALL “A” ALL “E” ALL “I” ALL “O” ALL “U”
Substituindo substrings
O comando INSPECT possui uma cláusula opcional chamada REPLACING que permite a substituição de strings dentro de uma variável alfanumérica. No exemplo abaixo todas as ocorrências de conteudo1 em variável será substituído por conteudo2:
INSPECT variável REPLACING ALL conteudo1 BY conteudo2
O comando INSPECT não pode inserir ou excluir caracteres de uma variável. Por esse motivo o conteúdo anterior e o conteúdo novo devem sempre a mesma quantidade de caracteres.
A opção REPLACING também permite a substituição de todos os caracteres antes ou depois de determinado delimitador:
03 EMAIL PIC X(100) VALUE “CONTATO@ME.COM”. ... DISPLAY “ANTES = “ EMAIL INSPECT EMAIL REPLACING CHARACTERS BY SPACES AFTER INITIAL “@” DISPLAY “DEPOIS = “ EMAIL
…mostraria:
ANTES = CONTATO@ME.COM DEPOIS = CONTATO@
E existem outras opções posicionais:
Existe um outro formato do comando INSPECT que não é a ideal para a substituição de substrings mas pode facilitar muito a conversão de caracteres.
INSPECT variável CONVERTING literal1 TO literal2
Esse comando é mais prático quando precisamos substituir um conjunto de caracteres por outro, pois todos eles podem ser declarados num único literal. O comando substitui o primeiro caracter de literal1 pelo primeiro caracter de literal2, o segundo caracter de literal1 pelo segundo caracter de literal2 e assim sucessivamente.
Veja alguns exemplos:
Processamento de strings, na prática
Vamos ver um exemplo real em que o dado precisa ser processado caracter a caracter. Vamos aproveitar e rever algumas operações de entrada e saída com arquivos indexados.
Cada registro do cadastro de clientes que usamos em alguns exemplos anteriores está com o campo NR-TELEFONE-1 editado de uma maneira diferente, situação muito comum em sistemas legados. Precisamos construir um programa que altere esse campo padronizando a edição do número de telefone da seguinte maneira:
- Para telefones fixos: (AA) PPPP-MMMM, onde AA é o código de área, PPPP é o prefixo de quatro dígitos dos telefones fixos e MMMM é a milhar
- Para telefones móveis: (AA) PPPPP-MMMM, onde AA é o código de área, PPPPP é o prefixo de cinco dígitos dos telefones móveis e MMMM é a milhar.
O quadro abaixo mostra como estão os telefones nesse momento e como eles devem ficar após a execução do programa:
Repare que existem registros onde o telefone foi carregado sem edição nenhuma, outros que estão sem código de área, outros ainda editados de com pontos no lugar dos traços… e até alguns que estão com a edição correta.
Nosso próximo programa precisa ler todos os registros desse cadastro e padronizar a edição para que todos os telefones fiquem como aparece na terceira coluna.
Vamos quebrar o problema em sete passos:
- Eliminar caracteres não numéricos. Vamos substituir todos os parênteses, traços e pontos por espaços. O telefone do cliente 003502, por exemplo, passaria de “31-3561-1973” para “ 31 3561 1973”.
- Separar o número de telefone em campos menores, delimitados por espaços. O telefone do cliente 003502 seria dividido em três variáveis: a primeira ficaria com “31”, a segunda com “3561” e a terceira com “1973”.
- Reagrupar os campos menores, aproveitando apenas os caracteres numéricos. O telefone do cliente 003502 ficaria com “3135611973”
- Verificar o tamanho da string resultante. O tamanho da string é que vai nos ajudar a decidir se o telefone é fixo ou móvel. Um tamanho de 8 caracteres significa que o telefone é fixo e está sem código de área. Um tamanho 9 significa que o telefone é móvel e também está sem código de área. Tamanho 10 indica que o telefone é fixo mas está com código de área preenchido. Tamanho 11 corresponde a um telefone móvel com código de área preenchido.
- Determinar código de área. Como alguns telefones estão sem código de área, precisamos definir um critério para determiná-lo durante a execução do programa. Nosso cadastro hipotético só tem clientes dos estados do Rio de Janeiro e de Minas Gerais. Logo, o código de área será 21 para RJ e 31 para MG.
- Aplicar uma máscara de edição ao número de telefone. Se o telefone for fixo, a edição será (AA) PPPP-MMMM. Se o telefone for móvel a edição será (AA) PPPPP-MMMM. Os caracteres que usaremos para preencher AA, PPPP, PPPPP e MMMM vai depender da quantidade de caracteres existentes no telefone reagrupado, que calculamos no passo 4.
- Regravar registro do cadastro de clientes com o número de telefone editado.
O programa acessará apenas o cadastro de clientes, arquivo CRA0201. A codificação da IDENTIFICATION, da ENVIRONMENT e da FILE SECTION não têm nenhuma particularidade, por isso veremos o passo a passo para construção do programa a partir da WORKING. Você poderá conferir o programa completo mais adiante nesse capítulo.
Começamos com o file status do cadastro de clientes…
*================================================================* WORKING-STORAGE SECTION. *----------------------------------------------------------------* 01 WT-FILE-STATUS. 03 WT-ST-CRA0201 PIC X(002) VALUE SPACES.
E em seguida criamos dois itens de grupo que usaremos para edição de telefones fixos e móveis. O que muda nesses dois campos é o tamanho do item elementar chamado prefixo, que possui 4 caracteres para telefones fixos e 5 caracteres para telefones móveis:
01 WT-TELEFONE-FIXO. 03 FILLER PIC X(001) VALUE "(". 03 WT-FIXO-AREA PIC X(002) VALUE SPACES. 03 FILLER PIC X(002) VALUE ")". 03 WT-FIXO-PREFIXO PIC X(004) VALUE SPACES. 03 FILLER PIC X(001) VALUE "-". 03 WT-FIXO-MILHAR PIC X(004) VALUE SPACES. 01 WT-TELEFONE-MOVEL. 03 FILLER PIC X(001) VALUE "(". 03 WT-MOVEL-AREA PIC X(002) VALUE SPACES. 03 FILLER PIC X(002) VALUE ")". 03 WT-MOVEL-PREFIXO PIC X(005) VALUE SPACES. 03 FILLER PIC X(001) VALUE "-". 03 WT-MOVEL-MILHAR PIC X(004) VALUE SPACES.
Por último declaramos algumas variáveis auxiliares. Precisamos de uma variável para calcular o tamanho dos strings que estiverem em cada telefone:
01 WT-AUXILIARES. 03 WT-AUX-TAMANHO PIC 9(002) VALUE ZEROS.
Em seguida, precisamos de algumas variáveis alfanuméricas que usaremos para quebrar o telefone do cliente em componentes menores. A quantidade de variáveis que precisaremos está diretamente relacionada às diferentes formas de edição dos telefones. Sabemos que o telefone será quebrado em componentes menores separados (delimitados) por espaços. Logo, “26416965” precisará apenas de uma variável; “31 3551 1283” precisaria de três… Vamos criar umas cinco. Podemos ajustar depois dos primeiros testes, se for necessário.
01 WT-AUXILIARES. 03 WT-AUX-TAMANHO PIC 9(002) VALUE ZEROS. 03 WT-AUX-PARTE-1 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-2 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-3 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-4 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-5 PIC X(015) VALUE SPACES.
Precisamos também de uma variável para reagrupar as partes que foram quebradas no passo anterior:
01 WT-AUXILIARES.
03 WT-AUX-TAMANHO PIC 9(002) VALUE ZEROS.
03 WT-AUX-PARTE-1 PIC X(015) VALUE SPACES.
03 WT-AUX-PARTE-2 PIC X(015) VALUE SPACES.
03 WT-AUX-PARTE-3 PIC X(015) VALUE SPACES.
03 WT-AUX-PARTE-4 PIC X(015) VALUE SPACES.
03 WT-AUX-PARTE-5 PIC X(015) VALUE SPACES.
03 WT-AUX-TELEFONE PIC X(015) VALUE SPACES.
E mais uma variável auxiliar para guardarmos o código de área que estabeleceremos a partir do Estado (RJ ou MG) de cada cliente:
01 WT-AUXILIARES. 03 WT-AUX-TAMANHO PIC 9(002) VALUE ZEROS. 03 WT-AUX-PARTE-1 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-2 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-3 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-4 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-5 PIC X(015) VALUE SPACES. 03 WT-AUX-TELEFONE PIC X(015) VALUE SPACES. 03 WT-AUX-AREA PIC X(002) VALUE SPACES.
O diagrama estruturado do nosso programa é bem simples. Toda a lógica de edição dos números de telefone acontecerá no parágrafo 2-PROCESSA, que será executado para todos os registros do cadastro de clientes:
O parágrafo 1-INICIA tem apenas a abertura do arquivo e a leitura do primeiro registro. Nossa intenção é processar todos os registros do arquivo de entrada e por isso precisamos acessá-lo sequencialmente. Mas sabemos que o book de declaração desse arquivo usa ACCESS MODE IS DYNAMIC. Logo, para ler esse arquivo sequencialmente precisamos complementar o comando READ com a cláusula NEXT:
*----------------------------------------------------------------*
* ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA
*----------------------------------------------------------------*
1-INICIA.
OPEN I-O CRA0201
READ CRA0201 NEXT.
Começamos o parágrafo 2-PROCESSA codificando o primeiro dos sete passos que descrevemos anteriormente. Precisamos substituir todos os caracteres não numéricos por espaços. Para isso, usaremos o comando INSPECT REPLACING:
*----------------------------------------------------------------* * ELIMINA TODOS OS CARACTERES NAO NUMERICOS, QUEBRA A VARIAVEL * EM COMPONENTES NUMERICOS, CONCATENA ESSES COMPONENTES, APLICA * UMAS MASCARA DE EDICAO AO NUMERO CONCATENADO E ATUALIZA O RE- * GISTRO COM O NUMERO EDITADO *----------------------------------------------------------------* 2-PROCESSA. * ELIMINA CARACTERES NAO NUMERICOS INSPECT CRA0201-NR-TELEFONE-1 REPLACING ALL "(" BY SPACE ALL ")" BY SPACE ALL "-" BY SPACE ALL "." BY SPACE
Você pode ver o efeito desse comando sobre os números de telefone na figura abaixo. Repare que, agora, só existem números e espaços nesse campo:
Nosso segundo passo precisa quebrar o número de telefone em partes delimitadas por espaços. O comando UNSTRING processa caracter a caracter e para quando não há mais caracteres no campo de origem. Esse Por esse motivo é possível que, em alguns casos, ele não precise de todas as cinco variáveis que usaremos como campo de destino. Como o UNSTRING não faz nenhum tipo de inicialização desses campos, precisamos garantir que, antes da sua execução, todas as variáveis sejam inicializadas com espaços.
* QUEBRA NUMERO DE TELEFONE EM COMPONENTES NUMERICOS MOVE SPACES TO WT-AUX-PARTE-1 MOVE SPACES TO WT-AUX-PARTE-2 MOVE SPACES TO WT-AUX-PARTE-3 MOVE SPACES TO WT-AUX-PARTE-4 MOVE SPACES TO WT-AUX-PARTE-5 UNSTRING CRA0201-NR-TELEFONE-1 DELIMITED BY ALL SPACES INTO WT-AUX-PARTE-1 WT-AUX-PARTE-2 WT-AUX-PARTE-3 WT-AUX-PARTE-4 WT-AUX-PARTE-5
O efeito desse comando pode ser visto na figura abaixo.
Repare que, em alguns casos, o UNSTRING não colocou nada na variável WT-AUX-PARTE-1. Isso aconteceu quando o número de telefone transitório começava com um espaço em branco. E esses números ficaram assim depois que substituímos os caracteres não numéricos por espaços.
Agora podemos reagrupar essas partes, também delimitadas por espaços, numa única variável. Como o comando STRING também não inicializa a variável de destino, moveremos espaços para WT-AUX-TELEFONE antes do comando:
* REAGRUPA COMPONENTES DO TELEFONE MOVE SPACES TO WT-AUX-TELEFONE STRING WT-AUX-PARTE-1 WT-AUX-PARTE-2 WT-AUX-PARTE-3 WT-AUX-PARTE-4 WT-AUX-PARTE-5 DELIMITED BY SPACE INTO WT-AUX-TELEFONE
Observe na figura abaixo que agora temos uma variável alfanumérica com todos os caracteres numéricos alinhados à esquerda:
Estamos quase prontos para mover o número de telefone para a variável editada. Antes disso, precisamos decidir se o telefone é fixo ou móvel, pois as máscaras de edição são diferentes. Para isso precisamos saber quantos caracteres estão preenchidos na variável auxiliar e faremos isso com o comando INSPECT TALLYING:
* OBTEM O TAMANHO DO TELEFONE APOS A CONCATENACAO MOVE ZEROS TO WT-AUX-TAMANHO INSPECT WT-AUX-TELEFONE TALLYING WT-AUX-TAMANHO FOR CHARACTERS BEFORE SPACE
Veja que usando a opção “FOR CHARACTERS” estamos contando quantos caracteres diferentes de espaços temos na variável WT-AUX-TELEFONE. O resultado desse comando é mostrado na figura abaixo:
Agora determinaremos o código de área em função do Estado onde cada cliente está localizado. A princípio precisamos fazer isso apenas para os telefones que estão sem código de área (aqueles que têm tamanho 8 ou 9). Para simplificar, testaremos o campo CD-ESTADO de todos os telefones e armazenaremos o código de área numa variável auxiliar:
* PREENCHE O CODIGO DE AREA EM FUNCAO DO CAMPO ESTADO IF CRA0201-CD-ESTADO = "RJ" MOVE "21" TO WT-AUX-AREA ELSE MOVE "31" TO WT-AUX-AREA END-IF
E agora estamos prontos para mover os telefones para as variáveis editadas que criamos na WORKING: WT-TELEFONE-FIXO e WT-TELEFONE-MOVEL. Faremos isso testando o tamanho que calculamos anteriormente.
* PREENCHE O NUMERO DE TELEFONE EDITADO DE ACORDO COM O TAMANHO * DO NUMERO RESULTANTE DA CONCATENACAO. * * SE TAMANHO FOR 8 * SIGNIFICA QUE E' UM TELEFONE FIXO SEM CODIGO DE AREA * * SE TAMANHO FOR 10 * SIGNIFICA QUE E' UM TELEFONE FIXO COM CODIGO DE AREA * * SE TAMANHO FOR 9 * SIGNIFICA QUE E' UM TELEFONE MOVEL SEM CODIGO DE AREA * * SE TAMANHO FOR 11 * SIGNIFICA QUE E' UM TELEFONE MOVEL COM CODIGO DE AREA EVALUATE WT-AUX-TAMANHO WHEN 8 MOVE WT-AUX-AREA TO WT-FIXO-AREA MOVE WT-AUX-TELEFONE(1:4) TO WT-FIXO-PREFIXO MOVE WT-AUX-TELEFONE(5:4) TO WT-FIXO-MILHAR MOVE WT-TELEFONE-FIXO TO CRA0201-NR-TELEFONE-1 WHEN 10 MOVE WT-AUX-AREA TO WT-FIXO-AREA MOVE WT-AUX-TELEFONE(3:4) TO WT-FIXO-PREFIXO MOVE WT-AUX-TELEFONE(7:4) TO WT-FIXO-MILHAR MOVE WT-TELEFONE-FIXO TO CRA0201-NR-TELEFONE-1 WHEN 9 MOVE WT-AUX-AREA TO WT-MOVEL-AREA MOVE WT-AUX-TELEFONE(1:5) TO WT-MOVEL-PREFIXO MOVE WT-AUX-TELEFONE(6:4) TO WT-MOVEL-MILHAR MOVE WT-TELEFONE-MOVEL TO CRA0201-NR-TELEFONE-1 WHEN 11 MOVE WT-AUX-AREA TO WT-MOVEL-AREA MOVE WT-AUX-TELEFONE(3:5) TO WT-MOVEL-PREFIXO MOVE WT-AUX-TELEFONE(8:4) TO WT-MOVEL-MILHAR MOVE WT-TELEFONE-MOVEL TO CRA0201-NR-TELEFONE-1 WHEN OTHER MOVE SPACES TO CRA0201-NR-TELEFONE-1 END-EVALUATE
Observe que estamos fazendo as movimentações usando modificadores de referência, pois eles nos permitem acessar substrings de uma string maior. Isso é necessário porque os componentes que queremos estão em posições diferentes, dependendo de como o telefone foi preenchido no passado. Por exemplo, e o tamanho do telefone for 8 (telefone fixo sem código de área), o prefixo estará nas posições 1 a 4 e a milhar nas posições 5 a 8. Já se o tamanho for 10 (telefone fixo com código de área), o prefixo estará nas posições 3 a 6 e a milhar nas posições 7 a 10. As variáveis editadas, depois de preenchidas, são mostradas na figura abaixo:
As variáveis editadas foram movidas para o campo do arquivo no próprio EVALUATE. Agora podemos regravar o registro e ler o próximo a ser processado:
* MOVE NUMERO EDITADO PARA REGISTRO E ATUALIZA ARQUIVO REWRITE CRA0201-REGISTRO READ CRA0201 NEXT.
Obviamente, poderíamos ter codificado esse programa sem nenhum comando especial para manipulação de strings. Com um monte de itens elementares, PERFORMs VARYING e IFs teríamos obtido os mesmos resultados. Ao usar UNSTRING, STRING, INSPECT e substrings, porém, conseguimos um programa menor e mais fácil de entender.
O programa completo você pode conferir abaixo:
*================================================================* IDENTIFICATION DIVISION. *----------------------------------------------------------------* PROGRAM-ID. CRP03021. AUTHOR. PAULO ANDRE DIAS. DATE-WRITTEN. 25/01/2017. REMARKS. *----------------------------------------------------------------* * SISTEMA: CR - CONTAS A RECEBER * JOB: 03 - ATUALIZACAO CADASTRAL * PROGRAMA: 02 - CORRIGE EDICAO DE NUMERO DE TELEFONE * * OBJETIVO: PADRONIZAR A EDICAO DOS NUMEROS DE TELEFONE RE- * GISTRADOS NO CADASTRO DE CLIENTES * * VERSOES: DATA DESCRICAO * ------ --------------------------------------- * XXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX * *----------------------------------------------------------------* *================================================================* ENVIRONMENT DIVISION. *----------------------------------------------------------------* CONFIGURATION SECTION. SPECIAL-NAMES. DECIMAL-POINT IS COMMA. INPUT-OUTPUT SECTION. FILE-CONTROL. * CADASTRO DE CLIENTES COPY CRS0201. *================================================================* DATA DIVISION. *----------------------------------------------------------------* FILE SECTION. * CADASTRO DE CLIENTES COPY CRF0201. *================================================================* WORKING-STORAGE SECTION. *----------------------------------------------------------------* 01 WT-FILE-STATUS. 03 WT-ST-CRA0201 PIC X(002) VALUE SPACES. 01 WT-TELEFONE-FIXO. 03 FILLER PIC X(001) VALUE "(". 03 WT-FIXO-AREA PIC X(002) VALUE SPACES. 03 FILLER PIC X(002) VALUE ")". 03 WT-FIXO-PREFIXO PIC X(004) VALUE SPACES. 03 FILLER PIC X(001) VALUE "-". 03 WT-FIXO-MILHAR PIC X(004) VALUE SPACES. 01 WT-TELEFONE-MOVEL. 03 FILLER PIC X(001) VALUE "(". 03 WT-MOVEL-AREA PIC X(002) VALUE SPACES. 03 FILLER PIC X(002) VALUE ")". 03 WT-MOVEL-PREFIXO PIC X(005) VALUE SPACES. 03 FILLER PIC X(001) VALUE "-". 03 WT-MOVEL-MILHAR PIC X(004) VALUE SPACES. 01 WT-AUXILIARES. 03 WT-AUX-TAMANHO PIC 9(002) VALUE ZEROS. 03 WT-AUX-PARTE-1 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-2 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-3 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-4 PIC X(015) VALUE SPACES. 03 WT-AUX-PARTE-5 PIC X(015) VALUE SPACES. 03 WT-AUX-TELEFONE PIC X(015) VALUE SPACES. 03 WT-AUX-AREA PIC X(002) VALUE SPACES. *================================================================* PROCEDURE DIVISION. *----------------------------------------------------------------* 0-PRINCIPAL. PERFORM 1-INICIA PERFORM 2-PROCESSA UNTIL WT-ST-CRA0201 NOT = "00" PERFORM 3-TERMINA STOP RUN. *----------------------------------------------------------------* * ABRE ARQUIVOS E LE PRIMEIRO REGISTRO DO ARQUIVO DE ENTRADA *----------------------------------------------------------------* 1-INICIA. OPEN I-O CRA0201 READ CRA0201 NEXT. *----------------------------------------------------------------* * ELIMINA TODOS OS CARACTERES NAO NUMERICOS, QUEBRA A VARIAVEL * EM COMPONENTES NUMERICOS, CONCATENA ESSES COMPONENTES, APLICA * UMAS MASCARA DE EDICAO AO NUMERO CONCATENADO E ATUALIZA O RE- * GISTRO COM O NUMERO EDITADO *----------------------------------------------------------------* 2-PROCESSA. * ELIMINA CARACTERES NAO NUMERICOS INSPECT CRA0201-NR-TELEFONE-1 REPLACING ALL "(" BY SPACE ALL ")" BY SPACE ALL "-" BY SPACE ALL "." BY SPACE * QUEBRA NUMERO DE TELEFONE EM COMPONENTES NUMERICOS MOVE SPACES TO WT-AUX-PARTE-1 MOVE SPACES TO WT-AUX-PARTE-2 MOVE SPACES TO WT-AUX-PARTE-3 MOVE SPACES TO WT-AUX-PARTE-4 MOVE SPACES TO WT-AUX-PARTE-5 UNSTRING CRA0201-NR-TELEFONE-1 DELIMITED BY ALL SPACES INTO WT-AUX-PARTE-1 WT-AUX-PARTE-2 WT-AUX-PARTE-3 WT-AUX-PARTE-4 WT-AUX-PARTE-5 * REAGRUPA COMPONENTES DO TELEFONE MOVE SPACES TO WT-AUX-TELEFONE STRING WT-AUX-PARTE-1 WT-AUX-PARTE-2 WT-AUX-PARTE-3 WT-AUX-PARTE-4 WT-AUX-PARTE-5 DELIMITED BY SPACE INTO WT-AUX-TELEFONE * OBTEM O TAMANHO DO TELEFONE APOS A CONCATENACAO MOVE ZEROS TO WT-AUX-TAMANHO INSPECT WT-AUX-TELEFONE TALLYING WT-AUX-TAMANHO FOR CHARACTERS BEFORE SPACE * PREENCHE O CODIGO DE AREA EM FUNCAO DO CAMPO ESTADO IF CRA0201-CD-ESTADO = "RJ" MOVE "21" TO WT-AUX-AREA ELSE MOVE "31" TO WT-AUX-AREA END-IF * PREENCHE O NUMERO DE TELEFONE EDITADO DE ACORDO COM O TAMANHO * DO NUMERO RESULTANTE DA CONCATENACAO. * * SE TAMANHO FOR 8 * SIGNIFICA QUE E' UM TELEFONE FIXO SEM CODIGO DE AREA * * SE TAMANHO FOR 10 * SIGNIFICA QUE E' UM TELEFONE FIXO COM CODIGO DE AREA * * SE TAMANHO FOR 9 * SIGNIFICA QUE E' UM TELEFONE MOVEL SEM CODIGO DE AREA * * SE TAMANHO FOR 11 * SIGNIFICA QUE E' UM TELEFONE MOVEL COM CODIGO DE AREA EVALUATE WT-AUX-TAMANHO WHEN 8 MOVE WT-AUX-AREA TO WT-FIXO-AREA MOVE WT-AUX-TELEFONE(1:4) TO WT-FIXO-PREFIXO MOVE WT-AUX-TELEFONE(5:4) TO WT-FIXO-MILHAR MOVE WT-TELEFONE-FIXO TO CRA0201-NR-TELEFONE-1 WHEN 10 MOVE WT-AUX-AREA TO WT-FIXO-AREA MOVE WT-AUX-TELEFONE(3:4) TO WT-FIXO-PREFIXO MOVE WT-AUX-TELEFONE(7:4) TO WT-FIXO-MILHAR MOVE WT-TELEFONE-FIXO TO CRA0201-NR-TELEFONE-1 WHEN 9 MOVE WT-AUX-AREA TO WT-MOVEL-AREA MOVE WT-AUX-TELEFONE(1:5) TO WT-MOVEL-PREFIXO MOVE WT-AUX-TELEFONE(6:4) TO WT-MOVEL-MILHAR MOVE WT-TELEFONE-MOVEL TO CRA0201-NR-TELEFONE-1 WHEN 11 MOVE WT-AUX-AREA TO WT-MOVEL-AREA MOVE WT-AUX-TELEFONE(3:5) TO WT-MOVEL-PREFIXO MOVE WT-AUX-TELEFONE(8:4) TO WT-MOVEL-MILHAR MOVE WT-TELEFONE-MOVEL TO CRA0201-NR-TELEFONE-1 WHEN OTHER MOVE SPACES TO CRA0201-NR-TELEFONE-1 END-EVALUATE * MOVE NUMERO EDITADO PARA REGISTRO E ATUALIZA ARQUIVO REWRITE CRA0201-REGISTRO READ CRA0201 NEXT. *----------------------------------------------------------------* * ENCERRAMENTO DO PROGRAMA *----------------------------------------------------------------* 3-TERMINA. CLOSE CRA0201.
Anterior | Conteúdo | Próxima |