Ybadoo - Soluções em Software Livre
Tutoriais
Programação Orientada a Objetos

Muitos pacotes de software para processamento de textos populares têm verificadores ortográficos incorporados. Usamos recursos de verificação ortográfica na preparação deste livro e descobrimos que, não importando o cuidado que pensávamos ter usado na preparação de um capítulo, o software sempre era capaz de encontrar mais alguns erros de ortografia além dos que havíamos descoberto manualmente.

Neste projeto, será pedido que você desenvolva o seu próprio utilitário de verificação ortográfica. Fazemos sugestões para ajudá-lo a começar. Você deve então pensar em adicionar mais recursos. Você pode achar útil usar um dicionário computadorizado como fonte de palavras.

Por que digitamos tantas palavras com erros de ortografia? Em alguns casos, simplesmente não conhecemos a grafia correta e, assim, "damos o chute que parece mais razoável". Em alguns casos, trocamos duas letras (por exemplo, "pardão" em vez de "padrão"). Algumas vezes, digitamos duas vezes a mesma letra acidentalmente (por exemplo, "dooce" em vez de "doce"). Algumas vezes, tocamos uma tecla próxima daquela que queríamos (por exemplo, "anibersário" ao invés de "aniversário"). E assim por diante.

Projete e implemente um programa de verificação ortográfica. O seu programa mantém um array wordList de strings de caracteres. Você pode digitar estes strings ou obtê-los de um dicionário computadorizado.

O seu programa solicita ao usuário que forneça uma palavra. O programa então procura aquela palavra no array wordList. Se a palavra consta no array, o seu programa deve imprimir Palavra está grafada corretamente.

Se a palavra não consta no array, seu programa deve imprimir Palavra não está grafada corretamente. Então, seu programa deveria procurar outras palavras em wordList, uma das quais pode ser a palavra que o usuário pretendia digitar. Por exemplo, você pode tentar todas as trocas simples de letras adjacentes no teclado para descobrir que a palavra "padrão" corresponde exatamente a uma das palavras em wordList. Naturalmente, isso implicaria que seu programa testasse todas as trocas simples, como "apdrão", "pardão", "padãro" e "padrão". Quando você encontra uma nova palavra igual a uma em wordList, imprima aquela palavra em uma mensagem tal como Você quis dizer "padrão"?.

Implemente outros testes, tais como substituir cada letra duplicada por uma única letra e quaisquer outros testes que você possa desenvolver para aumentar a utilidade do seu verificador ortográfico.

Desenvolva a solução solicitada, apresentando a modelagem do projeto em Unified Modeling Language (UML) e a sua implementação.

Deitel, H. M. (2001). C++, como programar. 3ª edição. Porto Alegre: Bookman. 1.098 páginas.

 

Diagrama de classes
Diagrama de classes da solução em Java

Arquivo Dictionary.java

/**
 * Copyright (C) 2009/2018 - Cristiano Lehrer (cristiano@ybadoo.com.br)
 *                  Ybadoo - Solucoes em Software Livre (www.ybadoo.com.br)
 *
 * Permission is granted to copy, distribute and/or modify this document
 * under the terms of the GNU Free Documentation License, Version 1.3
 * or any later version published by the Free Software Foundation; with
 * no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
 * A copy of the license is included in the section entitled "GNU
 * Free Documentation License".
 */

package com.ybadoo.tutoriais.poo;

import java.text.Collator;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;

/**
 * Classe responsavel pela representacao do dicionario
 */
public class Dictionary
{
  /**
   * Palavras cadastradas no dicionario
   */
  private Set<String> wordList;

  /**
   * Construtor padrao
   */
  public Dictionary()
  {
    wordList = new TreeSet<String>();
  }

  /**
   * Adicionar a palavra ao dicionario
   *
   * @param word palavra fornecida pelo usuario
   */
  public void add(String word)
  {
    wordList.add(word.toLowerCase());
  }

  /**
   * Verificar se a palavra esta presente no dicionario
   *
   * @param word palavra fornecida pelo usuario
   * @return true caso a palavra esteja presente no dicionario,
   *         false caso contrario
   */
  public boolean check(String word)
  {
    return wordList.contains(word.toLowerCase());
  }

  /**
   * Sugerir uma palavra do dicionario desconsiderando a acentuacao
   *
   * @param word palavra fornecida pelo usuario
   * @return palavra sugerida pelo dicionario
   */
  private String collators(String word)
  {
    Collator collator = Collator.getInstance (new Locale ("pt", "BR"));

    collator.setStrength(Collator.PRIMARY);

    for(String term: wordList)
    {
      if(collator.compare(term, word) == 0)
      {
        return term;
      }
    }

    return null;
  }

  /**
   * Sugerir uma palavra do dicionario atraves da distancia de Levenshtein
   *
   * @param word palavra fornecida pelo usuario
   * @return palavra sugerida pelo dicionario
   */
  private String levenshtein(String word)
  {
    int minimum = Integer.MAX_VALUE;

    String minimumText = null;

    for(String term: wordList)
    {
      word = word.toLowerCase().replaceAll ("(([A-Za-z])(\\2)+)", "$2");

      String termAux = term.replaceAll ("(([A-Za-z])(\\2)+)", "$2");

      int[] costs = new int[termAux.length() + 1];

      for(int j = 0; j < costs.length; j++)
      {
        costs[j] = j;
      }

      for(int i = 1; i <= word.length(); i++)
      {
        costs[0] = i;

        int nw = i - 1;

        for(int j = 1; j <= termAux.length(); j++)
        {
          int cj = Math.min(1 + Math.min(costs[j], costs[j - 1]), 
                 word.charAt(i - 1) == termAux.charAt(j - 1) ? nw : nw + 1);

          nw = costs[j];

          costs[j] = cj;
        }
      }

      if(costs[termAux.length()] == minimum)
      {
        if(prefixLength(word, termAux) > prefixLength(word, minimumText))
        {
          minimumText = term;
        }
      }
      else if(costs[termAux.length()] < minimum)
      {
        minimum = costs[termAux.length()];

        minimumText = term;
      }
    }

    return minimumText;
  }

  /**
   * Retornar o tamanho do prefixo entre duas palavras
   *
   * @param word1 primeira palavra
   * @param word2 segunda palavra
   * @return tamanho do prefixo entre duas palavras
   */
  private int prefixLength(String word1, String word2)
  {
    int length = 0;

    if(word1.length() < word2.length())
    {
      length = word1.length();
    }
    else
    {
      length = word2.length();
    }

    for(int i = 0; i < length; i++)
    {
      if(word1.charAt(i) != word2.charAt(i))
      {
        return i;
      }
    }

    return 0;
  }

  /**
   * Sugerir uma palavra do dicionario ao usuario
   *
   * @param word palavra fornecida pelo usuario
   * @return palavra sugerida pelo dicionario
   */
  public String suggest(String word)
  {
    String text = collators(word);

    if(text == null)
    {
      return levenshtein(word);
    }

    return text;
  }
}

Arquivo SpellCheck.java

/**
 * Copyright (C) 2009/2018 - Cristiano Lehrer (cristiano@ybadoo.com.br)
 *                  Ybadoo - Solucoes em Software Livre (www.ybadoo.com.br)
 *
 * Permission is granted to copy, distribute and/or modify this document
 * under the terms of the GNU Free Documentation License, Version 1.3
 * or any later version published by the Free Software Foundation; with
 * no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
 * A copy of the license is included in the section entitled "GNU
 * Free Documentation License".
 */

package com.ybadoo.tutoriais.poo;

import java.util.Scanner;

/**
 * Classe responsavel pela representacao de um corretor ortografico
 */
public class SpellCheck
{
  /**
   * Metodo principal da linguagem de programacao Java
   *
   * @param args argumentos da linha de comando (nao utilizado)
   */
  public static void main(String[] args)
  {
    Dictionary dictionary = new Dictionary();

    Scanner scanner = new Scanner(System.in);

    System.out.println("Inicializando o corretor ortográfico");
    System.out.println("Para finalizar, digite 'exit'");
    System.out.print("Forneça uma palavra: ");

    String word = scanner.nextLine();

    while(!"exit".equals(word.toLowerCase()))
    {
      if(dictionary.check(word))
      {
        System.out.println("Palavra está grafada corretamente");
      }
      else
      {
        System.out.println("Palavra não está grafada corretamente");

        String alternative = dictionary.suggest(word);

        if(alternative != null)
        {
          System.out.print("Você quis dizer \"" + alternative
            + "\"? (yes/no): ");

          String option = scanner.nextLine();

          if("no".equals(option.toLowerCase()))
          {
            System.out.print("Você gostaria de adicionar \"" + word
              + "\" ao dicionário? (yes/no): ");

            option = scanner.nextLine();

            if("yes".equals(option.toLowerCase()))
            {
              dictionary.add(word);

              System.out.println("\"" + word
                + "\" adicionado ao dicionário!");
            }
          }
        }
        else
        {
          System.out.print("Você gostaria de adicionar \"" + word
            + "\" ao dicionário? (yes/no): ");

          String option = scanner.nextLine();

          if("yes".equals(option.toLowerCase()))
          {
            dictionary.add(word);

            System.out.println("\"" + word
              + "\" adicionado ao dicionário!");
          }
        }
      }

      System.out.println();
      System.out.print("Forneça uma palavra: ");

      word = scanner.nextLine();
    }

    System.out.println("Finalizando o corretor ortográfico");
  }
}

Saída da solução em Java

Inicializando o corretor ortográfico
Para finalizar, digite 'exit'
Forneça uma palavra: padrão
Palavra não está grafada corretamente
Você gostaria de adicionar "padrão" ao dicionário? (yes/no): yes
"padrão" adicionado ao dicionário!

Forneça uma palavra: padrao
Palavra não está grafada corretamente
Você quis dizer "padrão"? (yes/no): yes

Forneça uma palavra: casa
Palavra não está grafada corretamente
Você quis dizer "padrão"? (yes/no): no
Você gostaria de adicionar "casa" ao dicionário? (yes/no): yes
"casa" adicionado ao dicionário!

Forneça uma palavra: pata
Palavra não está grafada corretamente
Você quis dizer "casa"? (yes/no): no
Você gostaria de adicionar "pata" ao dicionário? (yes/no): yes
"pata" adicionado ao dicionário!

Forneça uma palavra: pasa
Palavra não está grafada corretamente
Você quis dizer "pata"? (yes/no): yes

Forneça uma palavra: caasa
Palavra não está grafada corretamente
Você quis dizer "casa"? (yes/no): yes

Forneça uma palavra: exit
Finalizando o corretor ortográfico