miércoles, 16 de abril de 2014

Práctica prKWIC de Java

Buenas gente, por aquí estoy yo de nuevo. Se que vosotros quereis leer a Cris, pero ahora está en su pueblo y Blogger aún no permite publicar vía telegrama ni paloma mensajera.

Hoy os traigo la que, según creo, es la última práctica de Programación Orientada a Objetos de Primer año. De todos modos, si se me olvida alguna o hay alguna nueva siempre podéis avisarme y pasarme el enunciado ;)
Como siempre os dejo aquí linkeados el enunciado y la clase test.
Bueno, aquí voy con el enunciado:
El objetivo de esta práctica es realizar un glosario o índice de palabras atendiendo a su aparición en un conjunto de frases (KeyWord In Context, KWIC). La idea es analizar una colección de frases, extraer las distintas palabras que aparecen y construir una estructura que establezca una correspondencia entre cada palabra y el conjunto de frases en las que aparece. Para esta práctica será necesario repasar las clases String, StringBuilder y StringTokenizer, así como las clases correspondientes al marco de colecciones de java.
En concreto, se pide: 
a) Definir una clase Titulo que dé envoltura a una frase o título (de tipo String), y que permita
ordenar y comparar frases independientemente de si éstas contienen caracteres en minúsculas o
mayúsculas, así como un método String replace(String pal) para producir una cadena, a
partir del título, con las apariciones de la palabra pal sustituidas por "...". 
b) Definir una clase Indice que mantenga la información relativa a los caracteres separadores que se pueden presentar en los títulos y el índice (palabra -> conjunto de títulos en los que aparece) correspondiente a una colección de objetos de la clase Titulo. Esta clase tendrá:
- i. Dos constructores: uno con un argumento de tipo String con la relación de caracteres
separadores y otro con dos argumentos, uno de tipo String (como el anterior) y otro del
tipo Collection<String> con una relación de frases que habrá que analizar para
construir el correspondiente índice.
- ii. Un método void agregarTitulo(String t) para agregar un título al índice y otro
void agregarTitulo(Collection<String> ct) para agregar una colección de
títulos.
- iii. Un método String presentaIndice() que genere una presentación del índice de
forma que, cuando se imprima, quede como aparece en la salida del programa siguiente: 
Para las frases de entrada
“La rosa púrpura del Cairo”
“La rosa del azafrán”
“El color púrpura”
Salida:
AZAFRÁN
              La rosa del ...
CAIRO
              La rosa púrpura del ...
COLOR
              El ... púrpura
DEL
               La rosa ... azafrán
               La rosa púrpura ... Cairo
EL
               ... color púrpura
LA
               ... rosa del azafrán
               ... rosa púrpura del Cairo
PÚRPURA
               El color ...
               La rosa ... del Cairo
ROSA
               La ... del azafrán
               La ... púrpura del Cairo

c) Definir otra clase IndiceSignificativas, parecida a la clase Indice, que mantenga además
un conjunto de palabras que se consideran no significativas (artículos, preposiciones, conjunciones, …) y que ofrezca los mismos servicios con una diferencia de comportamiento en cuanto a las palabras que mantiene en el índice: sólo mantendrá las palabras significativas que aparezcan en los títulos. En concreto, esta clase tendrá dos constructores: uno con dos argumentos, el primero de tipo String con la relación de caracteres separadores y el segundo de tipo Collection<String> con una relación de palabras no significativas, y otro constructor con tres argumentos, el primero de tipo String con la relación de caracteres separadores, el segundo de tipo Collection<String> con una relación de frases que habrá que analizar para construir el correspondiente índice y el tercero de tipo Collection<String> con una relación de palabras no significativas.  
En este caso el método presentaIndice() generará una presentación del índice que,
cuando se imprima, quedará como aparece en la salida del programa siguiente: 
Para las frases de entrada
“La rosa púrpura del Cairo”
“La rosa del azafrán”
“El color púrpura”
Salida:
AZAFRÁN
               La rosa del ...
CAIRO
               La rosa púrpura del ...
COLOR
               El ... púrpura
PÚRPURA
               El color ...
               La rosa ... del Cairo
ROSA
               La ... del azafrán
               La ... púrpura del Cairo 
Probar el funcionamiento de las clases con la siguiente aplicación:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/*
public class Test {
 public static void main(String[] args) {
  String[] datos = { "La rosa púrpura del Cairo", "La rosa del azafrán",
    "El color Púrpura" };
  List<String> frases = Arrays.asList(datos);
  String separadores = " ,;.:()¿!¡?";
  Indice index = new Indice(separadores, frases);
  System.out.println(index.presentaIndice());
  String[] noSig = { "el", "ella", "la", "lo", "un", "una", "del" };
  Collection<String> colNoSig = Arrays.asList(noSig);
  IndiceSignificativas indexSig = new IndiceSignificativas(separadores,
    frases, colNoSig);
  System.out.println(indexSig.presentaIndice());
 }
}*/

public class Test {

 public static void main(String[] args) {

  String separadores = "[ ,;.:\\(\\)\\¿\\!\\¡\\?]+";
  //String separadores = " ,;.:()¿!¡?";

  try {
   Indice index = new Indice(separadores, "frases.txt");
   // para presentar por pantalla
   PrintWriter pw = new PrintWriter(System.out, true);
   index.presentaIndice(pw);
   // para guardar en fichero
   index.presentaIndice("salida.txt");

   // Ahora con palabrasNoSignificativas
   IndiceSignificativas indexSig = new IndiceSignificativas(
     separadores, "frases.txt", "noClaves.txt");
   // para presentar por pantalla
   indexSig.presentaIndice(pw);

   // para guardar en fichero
   indexSig.presentaIndice("salidaNoSig.txt");
  } catch (IOException e) {
   System.out.println("Error:" + e.getMessage());
  }
 }
}

Bueno, aquí os traigo los resultados: Primero la class Titulo:

public class Titulo implements Comparable<Titulo>{
 private String titulo;
 
 public Titulo(String t) {
  titulo = t;
 }
 
 public boolean equals(Object o) {
  return titulo.equalsIgnoreCase((String) o);
 }
 public int hashCode() {
  return titulo.hashCode();
 }
 @Override
 public int compareTo(Titulo tk) {
  return titulo.compareToIgnoreCase(tk.titulo);
 }
 
 public String toString() {
  return titulo;
 }
 public String replace(String pal) { //Devuelve la string original con las veces que aparezca pal cambiadas por "..." 
  StringBuilder sb = new StringBuilder(titulo);
  String palU = pal.toUpperCase();
  String sbU = sb.toString().toUpperCase();   //Stringbuilder a cadena y lo pasamos a mayuscula
  int ind = sbU.indexOf(palU);     //indexOf devuelve la posición de la primera aparicion de la palabra
  while (ind>=0) {         //  
   sb.replace(ind,  ind + pal.length(), "...");//Cambio el trozo de cadena de sb por el ...
   sbU = sb.toString().toUpperCase();   //Transformo el StringBuilder a cadena mayuscula de nuevo
   ind = sbU.indexOf(palU);     //vuelvo a buscar. Si no encuentra devuelve -1
  } 
  return sb.toString();
 }

}


Luego la class Indice:
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;


public class Indice {//Extrae de cada frase las palabras.
 protected SortedMap<String, SortedSet<Titulo>> indice;
 private String separadores;
 
 public Indice(String sep) {
  separadores = sep;
  indice = new TreeMap<String, SortedSet<Titulo>>();
 }
 public Indice(String sep, Collection<String> col) {
  this(sep);
  agregarTitulo(col);
 }
 public Indice(String sep, String filFrases) throws IOException {
  this(sep);
  agregarTituloFichero(filFrases);
 }
 
 public void agregarTitulo(Collection<String> col) {
  // TODO Auto-generated method stub
  for(String tit: col) {
   agregarTitulo(tit);
  }
 }
 public void agregarTitulo(String tit) {
  // TODO Auto-generated method stub
  //1º tokenizamos el titulo con los separadores
  Titulo tit2 = new Titulo(tit);
  StringTokenizer st = new StringTokenizer(tit, separadores);
  while(st.hasMoreTokens()) {
   String palabra = st.nextToken().toUpperCase();
   if(!indice.containsKey(palabra)) {
    indice.put(palabra, new TreeSet<Titulo>());
    indice.get(palabra).add(tit2);
    
   } else {
    indice.get(palabra).add(tit2);
   }
  }
 }
 public void agregarTitulo(Scanner sc) {
  while(sc.hasNextLine()) {
   String linea = sc.nextLine();
   agregarTitulo(linea);
  }
 }
 public void agregarTituloFichero(String filFrases) throws IOException {
  Scanner sc = new Scanner(new File(filFrases));
  agregarTitulo(sc); //Método auxiliar
  sc.close();
 }
 public String presentaIndice() {
  String str = "";
  for(String pal : indice.keySet()) {          //recorre las palabras clave 
   str = str + pal + "\n";
   for(Titulo tit : indice.get(pal)) {         //Nos da los titulos de cada palabra clave
    str = str + "\t" + tit.replace(pal);
    str = str + "\n";
   }
  }
  return str;
 }
 
 public void presentaIndice(String salida) throws IOException{
  PrintWriter pw = new PrintWriter(salida);
  presentaIndice(pw);
  pw.close();
 }
 public void presentaIndice(PrintWriter pw){
  for(String pal : indice.keySet()){        //Estos dos bucles podrían cambiarse por un simple
   pw.println(pal);        //pw.println(presentaIndice());
   for(Titulo tit : indice.get(pal)) {
    pw.println("\t" + tit.replace(pal));
   }
  }
 }
}

Y por último la class IndiceSignificativas:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;


public class IndiceSignificativas extends Indice{
 private SortedSet<String> noSignificativas;
 
 public IndiceSignificativas(String sep, Collection<String> noSig) {
  super(sep);
  //la coleccion las recorre, pasa a mayusculas y las mete en el conjunto de forma ordenada
  noSignificativas = new TreeSet<String>();
  for(String str : noSig) {
   noSignificativas.add(str.toUpperCase());
  }
 }
 public IndiceSignificativas(String sep, Collection<String> col, Collection<String> noSig){ //Falta Otro Constructor
  this(sep, noSig);
  this.agregarTitulo(col);
 }
 public IndiceSignificativas(String sep, String fichNoSig) throws IOException {
  super(sep);
  noSignificativas = new TreeSet<String>();
  palabrasNoSignificativas(fichNoSig);
  
 }
 public IndiceSignificativas(String sep, String fich, String fichNoSig) throws IOException {
  super(sep, fich);
  noSignificativas = new TreeSet<String>();
  palabrasNoSignificativas(fichNoSig);
  
 }

 public void palabrasNoSignificativas(String filNoSig) throws FileNotFoundException {
  Scanner sc = new Scanner(new File(filNoSig));
  palabrasNoSignificativas(sc);
 }
 public void palabrasNoSignificativas(Scanner sc)  {
  while(sc.hasNext()) {
   String linea = sc.next();
   noSignificativas.add(linea);
  }
 }
 public String presentaIndice() {
  String str = "";
  for(String pal : indice.keySet()) {          //recorre las palabras clave 
   if(!noSignificativas.contains(pal)) {
    str = str + pal + "\n";
    for(Titulo tit : indice.get(pal)) {         //Nos da los titulos de cada palabra clave
     str = str + "\t" + tit.replace(pal);
     str = str + "\n" + "\n";
    }
   }
   
  }
  return str;
 }
 public void presentaIndice(String salida) throws IOException{
  PrintWriter pw = new PrintWriter(salida);
  presentaIndice(pw);
  pw.close();
 }
 public void presentaIndice(PrintWriter pw){
  for(String pal : indice.keySet()){        //Estos dos bucles podrían cambiarse por un simple
   if(!noSignificativas.contains(pal.toLowerCase())) {
     pw.println(pal);        //pw.println(presentaIndice());
     for(Titulo tit : indice.get(pal)) {
      pw.println("\t" + tit.replace(pal));
     }
   }
   
  }
 }
 
}

Bueno gente, espero que os hayan gustado mis entradas de POO y os hayan sido de gran ayuda para aprobar ésta asignatura con buena nota ^^ Eso no significa que me vaya, aún quedan muchas cosas por subir :P

Hasta la próxima!! ;)

Actualización: He encontrado los archivos de entrada y salida y os los linkeo aquí:

Frases. 
Noclaves.
Salida
SalidanoSig

2 comentarios:

  1. Buenas, llevo un par de semanas viendo el blog y no está nada mal. Me ha servido de mucho, muchas gracias! Eso sí, estaría muy bien que pusieses más comentarios en el código, porque yo por ejemplo, las colecciones no acabo de pillarlas, y aunque tenga la solución delante, me cuesta ver lo que haces.

    ResponderEliminar
    Respuestas
    1. ¡Muchas gracias, intentaremos comentar más los códigos a partir de ahora! ;)

      Eliminar