VBA - Artigo 019 - Dominando strings

Progredindo em VBA no Microsoft Excel

Dominando strings

Manipulação de strings é uma das tarefas mais comuns em qualquer linguagem de programação e no VBA não é diferente. Seja para efetuar tratamento de entradas em formulários, compor frases que serão enviadas ao usuário, manipular registros de arquivos ou mesmo fazer comunicação com banco de dados, saber lidar com strings é essencial.

O VBA possui várias funções que lidam com strings. Vamos ver algumas funções básicas que você certamente deve conhecer:

- Len(string): Retorna o comprimento da string;

- LCase(string): Converte a string para letras minúsculas;

- UCase(string): Converte a string para letras maiúsculas;

- Str(número): Converte um número em uma string;

- Trim(string): Remove os espaços extras à esquerda e à direita da string fornecida;

- LTrim(string): Remove os espaços extras à esquerda da string fornecida;

- RTrim(string): Remove os espaços extras à direita da string fornecida;

- Left(string, quantidade): Retorna a quantidade de caracteres à esquerda da string fornecida (também pode ser usado Left$);

- Right(string, quantidade): Retorna a quantidade de caracteres à direita da string fornecida (também pode ser usado Right$);

- Mid(string, posição, quantidade): Retorna a quantidade de caracteres a partir da posição da string fornecida, lembrando que a posição inicial é 1 (também pode ser usado Mid$);

- Chr(valorASCII): retorna o caractere referente ao valor ASCII fornecido (também pode ser usado Chr$). É extremamente útil para representar caracteres que não podem ser colocados dentro de strings, como o Enter (valor 13) e as aspas duplas (valor 34). Permite mais flexibilidade nos textos em caixas de mensagem (MessageBox), por exemplo.

Em relação às quatro últimas, temos versões com e sem o caracter $. Qual é a diferença entre elas? Esta é uma dúvida muito comum. A diferença é que a versão com $ retornam uma string, enquanto as versões sem $ retornam o formato Variant. Aparentemente essa diferença não tem a mínima importância, mas se houver algum valor nulo, as versões com $ retornarão uma mensagem de erro, pois o formato string não consegue lidar com valores nulos. Esse é um tipo de erro mais comum no Access, pois os campos podem ter valores nulos. Como no Excel dificilmente teremos células ou formulários retornando valores nulos, é preferível usar sempre a versão com $, que tem um desempenho melhor, o que faz muita diferença em processamentos com milhares de iterações.

Existem funções para localizar textos em strings. InStr é a mais conhecida, mas não a única. Vejamos:

- InStr([posição], string, substring, [comparação]): Localiza uma substring em uma string a partir de uma posição específica. A posição é opcional, o valor padrão é 1 (início). Retorna a posição onde a substring começa dentro da string, caso não seja encontrado retorna 0;

- InStrRev(string, substring, [posição], [comparação]): Localiza uma substring em uma string a partir da direita. A posição é opcional, o valor padrão é -1 (final). Retorna a posição onde a substring começa dentro da string a partir da esquerda, caso não seja encontrado retorna 0.

Perceba que a ordem dos parâmetros é diferente e que a posição retornada é sempre a partir da esquerda para a direita, mesmo no InStrRev.

O parâmetro opcional de comparação pode ter três valores: vbBinaryCompare (ou 0, valor padrão), vbTextCompare (ou 1) e vbUseCompareOption (ou -1). O primeiro faz uma comparação exata, ou seja, busca exatamente o que está sendo pesquisado, enquanto o segundo efetua pesquisa por texto, não fazendo distinção entre maiúsculas e minúsculas. O último será explicado mais adiante. Teste os exemplos abaixo na área de verificação imediata do Editor de VBA:

? InStr(1, "ABC", "a", vbBinaryCompare)
0
? InStr(1, "ABC", "a", vbTextCompare)
1

O primeiro retorna 0, pois não encontrou por ser uma pesquisa por valor exato, enquanto o segundo encontrou por ser uma pesquisa por texto.

Outra função importante é Replace, que substitui texto em strings seguindo critérios fornecidos. Sua forma é a seguinte:

Replace(string, localizarsubstring, substituirsubstring, [início], [quantidade], [comparação]): Localiza uma substring dentro de uma string, se encontrar, substitui por uma outra substring. O parâmetro opcional início determina a partir de que caractere deve ser retornado (exclui os caracteres anteriores). O parâmetro opcional quantidade determina quantas substituições serão realizadas. Por fim, o parâmetro comparação funciona de maneira similar ao visto em InStr e InStrRev, com a diferença que o valor padrão é o vbUseCompareOption. Teste os exemplos abaixo na área de verificação imediata do Editor de VBA:

? Replace("123456789012345678901234567890", "5", "x")
1234x678901234x678901234x67890
? Replace("123456789012345678901234567890", "5", "x", 3)
34x678901234x678901234x67890
? Replace("123456789012345678901234567890", "5", "x", ,2)
1234x678901234x678901234567890
? Replace("ABCDEF", "c", "x", , ,vbBinaryCompare)
ABCDEF
? Replace("ABCDEF", "c", "x", , ,vbTextCompare)
ABxDEF

Como funciona o parâmetro vbUseCompareOption? Se você já tem alguma experiência em VBA, sabe que podemos usar o parâmetro Option Explicit no começo do módulo para obrigar a declaração de todas as variáveis. Da mesma forma, temos o parâmetro Option Private Module, para impedir que as funções codificadas no módulo sejam usadas em células do Excel. O parâmetro Option Compare tem dois valores possíveis: Binary ou Text. Option Compare Binary define que as comparações serão exatas, enquanto Option Compare Text define que as comparações serão por texto (desconsidera distinções entre maiúsculas e minúsculas). Quando não especificado, o valor padrão é Binary.

É importante observar que, se não houver nada especificando, as comparações serão feitas de modo binário. Se for usar Option Compare Text, lembre-se que em InStr e InStrRev o valor padrão é vbBinaryCompare. Na minha opinião, é melhor sempre usar vbTextCompare quando for necessário comparar por texto, pois deixa mais específico na própria linha qual o tipo de comparação está sendo feita, ajudando muito em futuras manutenções. Lembre-se também que o código fica mais autodocumentado quando usamos as enumerações ao invés dos valores numéricos.

Existem algumas funções pouco conhecidas e menos utilizadas, mas que é bom conhece-las porque pode ser que um dia haja a necessidade de usar alguma delas.

Asc(caracter): Retorna o valor ASCII correspondente ao caractere fornecido, ou seja, faz o oposto da função Chr/Chr$. Se esta função receber uma string com mais de um caractere, o valor retornado se refere ao primeiro.

StrComp(string1, string2, [comparação]): Efetua comparação entre duas strings e retorna um valor de acordo com o resultado da comparação. Se ambas forem iguais, retorna 0. Se em uma ordenação a string1 se posicionar antes de string2, retorna -1, caso contrário retorna 1. Se alguma das strings tiverem valor nulo, retorna Null. O parâmetro de comparação funciona de forma idêntica à função Replace, com valor padrão vbUseCompareOption.

StrConv(string, conversão, [LCID]): Converte uma string de acordo com o parâmetro de conversão, que pode ter os seguintes valores:

- vbUpperCase (ou 1): Converte para letras maiúsculas, de forma idêntica à função UCase;
- vbLowerCase (ou 2): Converte para letras minúsculas, de forma idêntica à função LCase;
- vbProperCase (ou 3): Converte de modo a deixar as iniciais das palavras em maiúsculas e o restante em minúsculas;
- vbUnicode (ou 64): Converte a string para o formato Unicode;
- vbFromUnicode (ou 128): Converte a string do formato Unicode para o formato padrão do sistema.

Há também os valores vbWide (ou 4) e vbNarrow (ou 8), que convertem caracteres entre padrões do leste asiático, e os valores vbKatakana (ou 16) e vbHiragana (ou 32), que convertem caracteres entre padrões japoneses.

O parâmetro opcional LCID se refere ao código de identificação do local. Quando não for especificado, utiliza o código do sistema.

Split(string, [delimitador], [limite], [comparação]): Separa a string em substrings separadas pelo delimitador. Note que o resultado deve ser armazenado em uma variável do tipo array, cujo índice começa no valor 0. Se o parâmetro delimitador não for especificado, será considerado o caractere de espaço. O parâmetro limite define quantas substrings serão retornadas; se o limite for 1 retorna a string inteira, se for 2 faz a primeira separação pelo delimitador e o restante é guardado na segunda substring e assim por diante. Se não especificar um valor para limite, todas as separações possíveis serão feitas. Você pode encontrar o maior valor com a função UBound. O parâmetro de comparação funciona da mesma maneira da função Replace. Um exemplo para entender melhor o funcionamento do limite:

X = Split("Fulano de Tal")
? X(0)
Fulano
? X(1)
de
? X(2)
Tal

X = Split("Fulano de Tal", , 2)
? X(0)
Fulano
? X(1)
de Tal

Agora a parte mais legal: aplicar os conhecimentos. Suponha que queremos uma função que obtenha o primeiro nome de um nome fornecido e outra função que obtenha o último nome. Caso só tenha sido fornecido um nome, deve ser retornado o nome inteiro em ambas funções. Podemos fazer da seguinte forma:

Function PrimeiroNome(Nome As String) As String

    Dim Espaco As Integer
    Espaco = InStr(1, Nome, " ")

    If Espaco > 1 Then
        PrimeiroNome = Mid$(Nome, 1, (Espaco - 1))
    Else
        PrimeiroNome = Nome
    End If

End Function

Function UltimoNome(Nome As String) As String

    Dim Espaco As Integer
    Espaco = InStrRev(Nome, " ")

    If Espaco > 1 Then
        UltimoNome = Mid$(Nome, (Espaco + 1), Len(Nome))
    Else
        UltimoNome = Nome
    End If

End Function

Nessas rotinas coloquei uma variável Espaco para obter a posição do primeiro ou último espaço, de acordo com a função. Caso encontrado (Espaco > 1) , o retorno é gerado usando o Mid$ (poderia ser usado o Left$ na primeira função e o Right$ na segunda, mas nesta última envolveria mais cálculos). Caso não encontre espaço, retorna a string inteira.
Vejamos agora as mesmas funções criadas com a função Split:

Function PrimeiroNome(Nome As String) As String

    Dim Nomes As Variant
   
    Nomes = Split(Nome)
   
    PrimeiroNome = Nomes(0)

End Function

Function UltimoNome(Nome As String) As String

    Dim Nomes As Variant
   
    Nomes = Split(Nome)
   
    UltimoNome = Nomes(UBound(Nomes))

End Function

Foi criada a variável Nomes do tipo variant para receber o array de nomes em ambas funções. A partir daí, extrai o primeiro (com índice 0) ou o último (UBound(Nomes) retorna o último índice do array).

As duas versões de cada função fazem exatamente a mesma coisa, a diferença é a quantidade de instruções utilizadas, o que impacta no desempenho. Se o uso for ocasional, o impacto é mínimo, mas se houver uma estrutura de repetição executando milhares de vezes o impacto será perceptível.

Podemos também criar uma função PCase, para simplificar o uso da função StrConv com parâmetro vbProperCase:

Function PCase(Texto As String) As String

    PCase = StrConv(Texto, vbProperCase)

End Function

Desta forma, você consegue uma forma mais simples e sem parâmetros do que escrever toda aquela linha para efetuar a conversão, funcionando da mesma forma que as funções nativas UCase e LCase.

Perceba que com o conhecimento das funções de strings é possível simplificar muito algumas tarefas repetitivas. Você pode até criar suas próprias funções para facilitar seu próprio código. Use o conhecimento a seu favor: automatize tarefas e simplifique seu código.

Pedro Martins


Formado em Tecnologia em Eletrônica Digital, já trabalhou como artefinalista, eletrotécnico, programador de CLP (para máquinas industriais) e analista de sistemas em sistema bancário, programando em COBOL.
Mexe com computadores e programação desde a segunda metade dos anos 1980, quando teve um MSX e aprendeu a programar em BASIC. É a favor da disseminação do conhecimento.






Catálogo de aulas (NOVIDADE)

Criei um catálogo de aulas para ajudar você em seus estudos. Acesse clicando na imagem abaixo ou clique aqui.


Postagem Anterior Próxima Postagem