Ver Mensaje Individual
  #7 (permalink)  
Antiguo 10/09/2004, 01:41
josemi
Ex Colaborador
 
Fecha de Ingreso: junio-2002
Mensajes: 9.091
Antigüedad: 21 años, 10 meses
Puntos: 16
Bueno, aqui va mi esbozo de aplicacion. Lee las notas finales.

Primero hagamos el pseudocodigo:
Código:
Abrir Entrada
Leer Primer Documento
Calcular terminos de busqueda y sus puntos
Inicializar Resultado
Mientras Leer Documento devuelva un documento
  Calcular terminos del documento y sus puntos
  Calcular puntuacion del documento y guardarlo
Fin mientras
Guardar resultado en fichero
El codigo PHP seria algo como:
Código PHP:
$input=file('input.txt');
$busqueda=leerDocumento($input);
$terminosBusqueda=array();
$terminosBusqueda=calcularTerminos($busqueda);
$resultado=array();
while (
false!=($documento=leerDocumento($input))) {
    
$terminosDoc=array();
    
$terminosDoc=calcularTerminos($documento);
    
$resultado[]=round(calcularPuntuacionDoc($terminosBusqueda,$terminosDoc),2);
}
$fo=fopen('output.txt','w');
fwrite($fo,join("\n",$resultado)); // en lugar de \n podria ser \r\n, dependiendo del SO
fclose($fo); 
Bien, ahora toca a las funciones. Empecemos por leerDocumento(). Le pasamos el array con toda la entrada. Devuelve un array con las lineas correspondientes a un documento. Lleva un puntero interno que almacena el indice de la linea que toca leer. Se van leyendo lineas hasta que encuentras la cadena de fin de documento. Si el documento tiene 0 lineas, se devuelve false, porque se ha llegado al final del fichero (2 "fin de documentos" seguidos).

En pseudo codigo:
Código:
Mientras Linea actual sea distinta a FinDocumento
  Añadir Linea actual a documento
  Mover a siguiente Linea
Fin mientras
Mover a siguiente linea // para apuntar a la siguiente de FinDocumento
Si documento no tiene lineas devolver false (no mas documentos)
Devolver documento
Y lo implementamos usando static para la variable que lleva el puntero:
Código PHP:
function leerDocumento($entrada) {
    static 
$indice=0;
    if (
$indice>=count($entrada)) return false;  // si el puntero apunta mas alla del ultimo elemento, devolvemos false
    
$fd='----------';  // cadena Fin de Documento
    
$doc=array();  // inicializamos el documento
    
while ($fd!=trim($entrada[$indice])) { // usamos trim() para quitar el salto de linea (file() los deja)
        
$doc[]=$entrada[$indice];
        
$indice++;
    }
    
$indice++;
    if (
0==count($doc)) return false;  // no mas documentos
    
return $doc;

Pasamos a calcularTerminos(), recibe un documento y devuelve un array asociativo, cuyos indices son las palabras y los valores el numero de repeticiones. En pseudocodigo:
Código:
Inicializar lista terminos
Para cada linea del documento
  Sacamos un array con las palabras de la linea
  Para cada palabra
    Normalizamos la palabra
    Si la palabra normalizada no esta en la lista terminos
      Añadir a la lista con valor 1
    sino
      Incrementar el valor del termino en la lista
    Fin si
  Fin Para
Fin Para
Devolver Lista terminos
Implementado en PHP:
Código PHP:
function calcularTerminos($doc) {
    
$listaTerminos=array();
    foreach (
$doc as $linea) {
        
$terminos=explode(' ',$linea);
        foreach (
$terminos as $termino) {
            
$terminoNormalizado=normalizarTermino($termino);
            if (
''!=$terminoNormalizado) {
                if (isset(
$listaTerminos[$terminoNormalizado])) {
                    
$listaTerminos[$terminoNormalizado]++;
                } else {
                    
$listaTerminos[$terminoNormalizado]=1;
                }
            }
        }
    }
    return 
$listaTerminos;

normalizarTermino() se encarga de pasar cada termino al formato que te dicen, sin signos de puntuacion. Ademas, pasa el termino a minusculas, porque quieren que la comparacion sea case-insensitive. El codigo es auto explicativo:
Código PHP:
function normalizarTermino($palabra) {
    
$palabra=strtolower(trim($palabra));
    
$palabra=ereg_replace("[^a-z0-9]",'',$palabra);
    return 
$palabra;

OJO, no estoy seguro de la expresion regular, no son mi fuerte. Y a pesar de ser la mas sencilla, es la mas problematica. ¿Por que? Por el idioma. strtolower() puede no reconocer la Ñ y vocales acentuadas (y quizas Ç) como mayusculas y no pasarlas a minusculas. Y esos caracteres no estan en el intervalo a-z para los ingleses, asi que el ereg_replace() los eliminaria. Puedes buscar una solucion a eso (poner en minusculas "a mano" con strtr() y añadirlos en ereg_replace) o plantearlo asi, indicando el problema.

¿Que queda? Ya, calcularPuntuacionDoc(). Recibe 2 arrays con los terminos de busqueda y los del documento. La puntuacion es la suma de las raices cuadradas del producto de las repeticiones del termino. Creo que el codigo tambien es bastante directo:
Código PHP:
function calcularPuntuacionDoc($busq$doc) {
    
$puntuacion=0;
    foreach (
$busq as $termino => $puntBusq) {
        if (isset(
$doc[$termino])) {
            
$puntuacion+=sqrt($puntBusq*$doc[$termino]);
        }
    }
    return 
$puntacion;

Creo que esta claro: para cada termino de busqueda, miras si esta en en el documento y si esta, hayas el producto y calculas la raiz cuadrada. Si la palabra no esta en la lista de terminos de busqueda, o no esta en el documento, el producto siempre sera 0. La raiz cuadrada de 0 es 0. Asi que para la puntuacion del documento solo la calculas con los terminos que esten tanto en la busqueda como en el documento.

Y creo que ya esta todo.
ATENCION, el codigo no esta probado, lo he sacado directamente de mi cabeza. Puede tener errores. Lo ideal seria que tuviese un fichero de entrada de ejemplo con su salida correcta, para probar este codigo y comprobar que funciona (se hace asi siempre). OJO, tampoco he puesto controles de errores, como validacion de parametros y cosas asi.

Espero que te sirva de guia.
__________________
Josemi

Aprendiz de mucho, maestro de poco.

Última edición por josemi; 10/09/2004 a las 01:43