.NET

7 jun, 2016

VB .NET – Tratando strings e coleções de strings com LINQ

Publicidade

Neste artigo vou mostrar como podemos usar os recursos da LINQ – Language Integrated Query – para tratar strings e coleções de strings.

A LINQ pode ser usada para consultar e transformar strings e coleções de strings e este recurso pode ser muito útil, especialmente com dados estruturados em arquivos textos.

Podemos combinar as consultas LINQ com as funções strings tradicionais e com expressões regulares, aumentando, assim, o seu potencial de recursos. Dessa forma podemos:

  • Usar o método Split() para criar um array de strings que podemos consultar e modificar usando LINQ e também podemos usar usar o métodoIsMatch() na cláusula Where da consulta LINQ;
  • Usar a LINQ para consultar ou modificar o resultado MatchCollection retornado por uma expressão regular.

Assim podemos separar um texto fonte em palavras, sentenças, parágrafos, páginas e qualquer outro critério e, então, realizar consulta adicional.

Muitos tipos de arquivos textos consistem em uma série de linhas, com uma formatação padrão que usa vírgula, tab, arquivos delimitados, arquivos fixo etc. Após você ler esses arquivos, você pode usar a LINQ para consultar e modificar as linhas.

Esse artigo será útil para recordar os recursos da LINQ no tratamento de strings.

Recursos usados: Visual Studio Community 2015.

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto no VS Community

Abra o VS 2015 Community e clique em New Project. Selecione a linguagem Visual Basic e o template Windows Forms Application.

Informe o nome da solução como LINQ_Strings e clique no botão OK.

net_strlnq11

1. Contando as ocorrências de uma palavra em uma string

Como a classe string implementa a interface genérica IEnumerable(Of T), qualquer string pode ser consultada como uma sequência de caracteres (para operações mais complexas é aconselhável usar Regex).

Este exemplo mostra como podemos usar uma consulta LINQ para contar as ocorrências de uma palavra especificada em uma string.

Para realizar a tarefa, primeiro usamos o método Split para criar um array de palavras e isso tem um impacto no desempenho da aplicação; portanto, se a única tarefa é contar palavras, poderíamos usar os métodos Matches ou IndexOf.

Defina no formulário form1.vb os controles:

  • 1 Button – btnLerTexto

  • 1 TextBox – txtText, Multiline=True

  • 1 Button – btnContarOcorrencias

  • 1 Textbox – txtPalavra

  • 1 Button – btnLimpar

  • 1 ListBox – lbResultado

Disponha os controles no formulário conforme o leiaute da figura abaixo:

net_strlnq12

No evento Click do botão – btnLerTexto inclua o código que permite escolher um arquivo texto e exibir no formulário:

Private Sub btnLerTexto_Click(sender As Object, e As EventArgs) Handles btnLerTexto.Click
        Dim ofd1 As New OpenFileDialog
        ofd1.Title = "Selecionar Arquivo"
        ofd1.InitialDirectory = "C:\Dados\"
        'filtra para exibir somente arquivos textos
        ofd1.Filter = "Arquivos Texto (*.Txt)|*.Txt|" & "Todos Arquivos (*.*)|*.*"
        ofd1.CheckFileExists = True
        ofd1.CheckPathExists = True
        ofd1.FilterIndex = 1
        ofd1.RestoreDirectory = True
        ofd1.ReadOnlyChecked = True
        Dim dr As DialogResult = ofd1.ShowDialog()
        If dr = System.Windows.Forms.DialogResult.OK Then
            ' abre o arquivo e le o seu conteudo
            txtTexto.Text = My.Computer.FileSystem.ReadAllText(ofd1.FileName)
        End If
    End Sub

No evento Click do botão – btnContarOcorrencias – inclua o código que irá contar o número de ocorrências da palavra informada:

 Private Sub btnContarOcorrencias_Click(sender As Object, e As EventArgs) Handles btnContarOcorrencias.Click
        Dim palavraAlvo As String = txtPalavra.Text.Trim()
        If String.IsNullOrWhiteSpace(palavraAlvo) Then
            MessageBox.Show("Informe a palavra a ser contada na string")
            Exit Sub
        End If
        Dim fonteDados As String() = txtTexto.Text.Split(New Char() {" ", ",", ".", ";", ":", "-", ", ", "(", ")"}, StringSplitOptions.RemoveEmptyEntries)
        ' Cria e executa a consulta
        ' Ela é executada imediatamente porque um único valor é produzido
        ' Usamos ToLower para encontrar "xxx" e "XXX" 
        Dim resultado = From palavra In fonteDados
                                    Where palavra.ToLowerInvariant() = palavraAlvo.ToLowerInvariant()
                                    Select palavra
        'conta as ocorrências
        Dim valor As Integer = resultado.Count()
        'exibe o resultlado o listbox
        lbResultado.Items.Add(valor & " ocorrência da palavra """ & palavraAlvo & """ foram encontradas.")
    End Sub

Executando o projeto e fazendo alguns testes teremos o resultado abaixo:

net_strlnq14

2. Combinando Consultas LINQ com expressões regulares

Vamos realizar agora uma consulta mais complexa usando LINQ e expressões regulares. Vamos supor que desejamos verificar a ocorrência de uma palavra em arquivos HTML (.htm).

Depois, vamos incluir um novo formulário no projeto atual e definir uma interface simples e intuitiva usando os seguintes controles:

  • 1 TextBox – txtLocal

  • 1 Button – btnLocalBusca

  • 1 TextBox – txtPalavra

  • 1 Button – btnOcorrencias

  • 1 ListBox – lbResultado

No evento Click do botão btnLocalBusca, inclua o código que permite selecionar uma pasta a partir de onde serão lidos os arquivos para realizar a busca:

Private Sub btnLocalBusca_Click(sender As Object, e As EventArgs) Handles btnLocalBusca.Click
        Dim fbd1 As New FolderBrowserDialog
        fbd1.Description = "Selecione uma pasta para busca"
        fbd1.RootFolder = Environment.SpecialFolder.MyComputer
        fbd1.ShowNewFolderButton = True

        'Exibe a caixa de diálogo
        If fbd1.ShowDialog = DialogResult.OK Then
            'Exibe o nome da pasta no textbox
            txtLocal.Text = fbd1.SelectedPath.ToString()
        End If
End Sub

A seguir, no evento Click do botão – btnOcorrencias -, temos o código que percorre todos os arquivos com extensão .htm da pasta e faz a busca por ocorrências nos arquivos da palavra definida para critério de busca:

Private Sub btnOcorrencias_Click(sender As Object, e As EventArgs) Handles btnOcorrencias.Click
        Dim pastaBusca As String = txtLocal.Text.Trim
        Dim listaArquivos As IEnumerable(Of FileInfo) = ObtemArquivos(txtLocal.Text.Trim)
        ' Cria uma expressão regular para encontrar as ocorrências do texto indicado
        Dim termoBusca As System.Text.RegularExpressions.Regex =
                                                  New System.Text.RegularExpressions.Regex(txtPalavra.Text.Trim)
        'define a consulta nos arquivos .htm do texto indicado
        Dim consultaArquivos = From _arquivo In listaArquivos
                                                  Where _arquivo.Extension = ".htm"
                                                  Let arquivoTexto = File.ReadAllText(_arquivo.FullName)
                                                  Let correspondencia = termoBusca.Matches(arquivoTexto)
                                                Where (correspondencia.Count > 0)
                                                 Select Name = _arquivo.FullName,
                                                        Matches = From match As System.Text.RegularExpressions.Match In correspondencia
                                                        Select match.Value
        ' Executa a consulta
        lbResultado.Items.Add("O termo " & termoBusca.ToString() & " foi encontrado em :")
        For Each arquivosCoincidentes In consultaArquivos
            Dim s = arquivosCoincidentes.Name.Substring(pastaBusca.Length - 1)
            lbResultado.Items.Add(s)
            For Each encontrado In arquivosCoincidentes.Matches
                lbResultado.Items.Add("  " + encontrado)
            Next
        Next
    End Sub

Abaixo temos o código do método ObtemArquivos que recebe a pasta de destino e obtém os arquivos contidos nesta pasta:

  Shared Function ObtemArquivos(ByVal raiz As String) As IEnumerable(Of System.IO.FileInfo)
        Return From arquivo In My.Computer.FileSystem.GetFiles(
                   raiz, FileIO.SearchOption.SearchAllSubDirectories, "*.*")

               Select New FileInfo(arquivo)

    End Function

Executando o projeto e fazendo alguns testes teremos o resultado abaixo:

net_strlnq13

Dessa forma, vimos como usar os recursos do LINQ para tratar strings e coleções.

Pegue o projeto completo aqui: LINQ_Strings.zip