Comunidad Game Maker

Ayuda => Desarrollo de Scripts => Mensaje iniciado por: Johann en Noviembre 02, 2018, 03:15:22 am

Título: Acortar y alargar strings segun caracteres repetidos
Publicado por: Johann en Noviembre 02, 2018, 03:15:22 am

Script para acortar una cadena de texto resumiendo la cantidad de caracteres repetidos sucesivos:
///shorten(str)
//
// (ESP)
// Reduce el tamaño de una cadena de texto
// reemplazando un conjunto de caracteres sucesivos
// por el numero de veces que se repite.
//
//     str      cadena de caracteres muy larga
//
// (ENG)
// Reduces the size of a text replacing a set of
// consecutive characters with the number of times
// it is present.
//
//     str      a very large string
//
//
/// GMLscripts.com/license
{
    var str = argument0
    var newStr = "";
    var currentChar;
    var nextChar;
    var size = string_length(str);
    var amount = 0;
    for (var i=1; i<=size; i++) {
        currentChar = string_char_at(str, i);
        if (i!=size) {
            nextChar = string_char_at(str, i+1);
        } else {
            nextChar = "";
        }
        if (currentChar == nextChar) {
            amount = 1;
            newStr += currentChar;
            while (currentChar == nextChar) {
                amount++;
                i++;
                nextChar = string_char_at(str, i+1);
            }
            newStr += ("(" + string(amount) + ")");
        } else {
            newStr += currentChar;
        }
    }
    return newStr;
}

Script para recuperar una cadena de texto reestableciendo la cantidad de caracteres repetidos sucesivos:
///enlarge(str)
//
// (ESP)
// Recupera el tamaño de una cadena de texto
// agregando un conjunto de caracteres sucesivos
// a partir del numero de veces que se repite.
//
//     str      cadena de caracteres a alargar
//
// (ENG)
// Recovers the size of a text adding a set of
// consecutive characters with the number of times
// it is needed.
//
//     str      a string to enlarge
//
//
/// GMLscripts.com/license
{
    var str = argument0;
    var oldStr = "";
    var currentChar;
    var nextChar;
    var size = string_length(str);
    var amount = "";
    for (var i=1; i<=size; i++) {
        currentChar = string_char_at(str, i);
        if (i!=size) {
            nextChar = string_char_at(str, i+1);
        } else {
            nextChar = "";
        }
        if (nextChar == "(") {
            amount = "";
            while (nextChar != ")") {
                i++;
                nextChar = string_char_at(str, i+1);
                amount += nextChar;
                show_debug_message(amount);
            }
            repeat(real(amount)) {
                oldStr += currentChar;
            }
            i++;
        } else {
            oldStr += currentChar;
        }
    }
    return oldStr;
}

Estos algoritmos se basan (se inspiran, mejor) en el algoritmo Run-length_encoding (https://es.wikipedia.org/wiki/Run-length_encoding) y he tenido que hacerlos para acortar y recuperar las cadenas de texto generadas por las funciones ds_*_write() donde el * es el nombre de una estructura de datos en GM, estas funciones retornan un string como el siguiente y su tamaño depende del contenido en la estructura de datos:

//Ejemplo
var text = ds_grid_write(my_grid);
show_debug_message(text);
var text2 = shorten(text);
show_debug_message(text2);

Código: [Seleccionar]
5A0200000400000004000000000000000000000000000000000000000000000000000040000000000000000000000040000000000000000000000040000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000
408 caracteres

5A020(5)40(7)40(52)40(23)40(23)40(23)40(95)40(95)40(73)
55 caracteres

Ya que requiero almacenar estos datos en una base de datos sqlite3 para generar unas estructuras visualmente en mi proyecto y no quería almacenar algo muy largo.
En resumen, el tamaño del texto se reduce en un 86.5% mejorando el consumo de memoria en disco, esto es importante para aplicaciones móviles.

Ojalá les gusten y puedan usarlos.
Mañana los posteo en https://www.gmlscripts.com y en el foro de yoyo, haber como me va por allá, por eso usé ese encabezado de comentarios.
Título: Re:Acortar y alargar strings segun caracteres repetidos
Publicado por: Ashe de Freljord en Noviembre 02, 2018, 03:49:17 am
Buenos scripts.

En el decodificador me parece que sería más optimo operar 10^N que hacer el ciclo N veces. Al menos las veces donde la seguidilla es de ceros.

Edit: Estuve pasando el codigo a C++ solo para practicar para la universidad XD
Y me dí cuenta que el código alarga la cadena para coincidencias de 2 y 3 caracteres, mientras que con 4 simplemente no hay optimizacion.

Ej:
a003315588800
13
a0(2)3(2)15(2)8(3)0(2)
22

Creo que sería bueno tener en cuenta esos casos en particular. 
Título: Re:Acortar y alargar strings segun caracteres repetidos
Publicado por: Goganpis en Noviembre 02, 2018, 02:27:04 pm
No pense, ni me imaginaba algo asi, unos de los algoritmos de gran utilidad, no pense en algo asi nunca xD... Que buen trabajo de script para adaptar Good Job!  ;D
Título: Re:Acortar y alargar strings segun caracteres repetidos
Publicado por: Johann en Noviembre 02, 2018, 10:24:43 pm
Ashe de Freljord, has obtenido lo que podríamos llamar el umbral de optimización del algoritmo, lo que me gustaría conocer es el tiempo de ejecución en diferentes casos.

Como lo hice pensando en los strings que genera ds_*_write() no caí en cuenta de esos casos, tienes razón, si los caracteres se repiten 4 veces o menos ya no vale la pena aplicar el algoritmo.

Pero si se fijan en los strings para todas las estructuras de datos del GM si que será muy útil, o al menos interesante.