Acerca de:

Este blog contiene los códigos, ejemplos y bases de datos que he usado cuando aprendía acerca de algún tema específico. En lugar de borrarlos (una vez dominado ya el tema), he decidido publicarlos :)

sábado, 10 de diciembre de 2016

Reemplazando subcadenas dentro de archivos de texto con Python

Sucede que tenía varios archivos de Inno Setup Script en una carpeta, los cuales apuntaban a archivos en otra carpeta que correspondían a los instaladores de distintas versiones de una aplicación (e incluso distintas versiones del mismo instalador), por lo que las rutas a los archivos dentro de los scripts eran rutas absolutas. Un día, al actualizar los códigos fuente y los compilados tuve que ponerlos en una nueva carpeta, y esto significada actualizar todas las rutas absolutas en los scripts de Inno Setup.

El siguiente ejemplo muestra cómo se ven mis scripts de Inno Setup, en la realidad incluyen muchos muchos más archivos (tomado de los ejemplos que vienen con el Inno Setup):

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma2
SolidCompression=yes
OutputDir=D:\Generated Installers\

[Files]
Source: "D:\compiled_2014\MyProg.exe"; DestDir: "{app}"
Source: "D:\compiled_2014\MyProg.chm"; DestDir: "{app}"
Source: "D:\compiled_2014\Readme.txt"; DestDir: "{app}"; Flags: isreadme

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"



Para evitar tener que hacer el cambio de rutas a mano, me creé este script en Python:

import os
import sys

iss = [c for c in os.listdir(sys.path[0]) if ".iss" in c]

for i in iss:
    fopen = open(i,'r')
    fwrite = []

    flines = fopen.readlines()
    fopen.close()

    for line in flines:
        fwrite.append(line.replace("D:\compiled_2014", "F:\compiled_Octubre_2016"))
           
    fopen = open(i,'w')
    fopen.writelines(fwrite)
    fopen.close()

   

Lo que hace este script en Python es reemplazar la ruta antigua (en este ejemplo "D:\compiled_2014") por la nueva ruta "F:\compiled_Octubre_2016" de todos los archivos .iss que encuentre en la misma carpeta donde está ubicado.
Finalmente, el script en Inno Setup queda así:

[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma2
SolidCompression=yes
OutputDir=D:\Generated Installers\

[Files]
Source: "F:\compiled_Octubre_2016\MyProg.exe"; DestDir: "{app}"
Source: "F:\compiled_Octubre_2016\MyProg.chm"; DestDir: "{app}"
Source: "F:\compiled_Octubre_2016\Readme.txt"; DestDir: "{app}"; Flags: isreadme

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"

lunes, 28 de noviembre de 2016

Imprimir caracteres en consola con Visual C++

Al crear una aplicación de consola con Visual C++ Express encontré que no es tan intuituvo como creí (hay que importar más librerías de las que pensé, especialmente si se trabaja con arreglos de caracteres que se convierten a string). Al final, éste es el código que funcionó:


#include "stdafx.h"
#include
<iostream>
#include
<ostream>
#include
<string>

using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
    unsigned char* chararr = new unsigned char[256];

    // ... asigno valores al array de caracteres...   

    string str;
    str.assign((char*)chararr);   

  
    cout << "Look, I'm writting string values"
    cout << str << "\n";
   
    cout << "Look, I'm writting hexadecimal values";   

    for (unsigned long i = 0; i < 256; i++)
         printf("%02X ", chararr[i]);


    printf("\n");

}

martes, 25 de octubre de 2016

Cómo obtener información de la distro de Linux con Python 2.7

El siguiente código muestra en pantalla información sobre la distro de linux y la versión de java instalada en caso de existir:

import platform
import subprocess

print platform.architecture()
print platform.linux_distribution()
ret = subprocess.call('java -version', shell = True)



A continuación está lo que me imprimieron algunas distros:

centos 7 x64 por defecto:

('64bit', 'ELF')
('centos', '7.1.1503', 'Core')
java version "1.7.0_91"
OpenJDK Runtime Environment (rhel-2.6.2.1.el7_1-x86_64 u91-b00)
OpenJDK 64-Bit Server VM (build 24.91-b01, mixed mode)

Centos 6 x64 con Oracle Java 8:

('64bit', 'ELF')
('centos', '6.5', 'Final')
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

Ubuntu 14 x32 con Oracle Java 8:

('32bit', 'ELF')
('Ubuntu', '14.04', 'trusty')
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) Server VM (build 25.65-b01, mixed mode)

Linux Mint 17 x32 por defecto:

('32bit', 'ELF')
('LinuxMint', '17.2', 'rafaela')
java version "1.7.0_79"
OpenJDK Runtime Environment (IcedTea 2.5.5) (7u79-2.5.5-0ubuntu0.14.04.2)
OpenJDK Server VM (build 24.79-b02, mixed mode)

Codingground webpage ide:

('64bit', '')
('Fedora', '23', 'Twenty Three')
openjdk version "1.8.0_72"
OpenJDK Runtime Environment (build 1.8.0_72-b15)
OpenJDK 64-Bit Server VM (build 25.72-b15, mixed mode)

Ideone webpage ide:

('32bit', '')
('debian', 'stretch/sid', '')

viernes, 2 de septiembre de 2016

Cómo evitar que C++ decore los nombres de las funciones de una dll

Agradezco la ayuda a:
http://stackoverflow.com/q/2804893
http://stackoverflow.com/q/1467144

Mi caso era que estaba compilando una dll en c++ con Visual Studio Express 2013 y encontré que, al intentar invocarla desde otra aplicación, el compilador decoraba los nombres de las funciones.
Para evitarlo, se deben declarar las funciones con extern "C":

En el archivo  .h:

extern "C" __declspec (dllexport) long SomeFunction(int param);

Y en el archivo .cpp respectivo:

extern "C" 
__declspec (dllexport) long SomeFunction(int param)
{
    return _somethingIwantToDo(param);
}


si se está depurando, es mejor dejar la opción de "Generar Información de Depuración" en "Si" o el depurador empezará a protestar:

Esto es mejor dejarlo en "Si".

Al colocar  extern "C" el compilador ya no decora los nombres de las funciones aunque la convención de llamada sea stdcall o cdecl:

 
Eso sí, la convención de llamada de la dll y la aplicación que la invoca debe ser la misma, o el compilador arrojará el error LNK2019 y de paso el LNK1120:


Cómo crear una ventana modal que envíe datos ingresados por el usuario en Java Swing

Agradezco la ayuda a:
http://stackoverflow.com/a/28461883
http://stackoverflow.com/a/4089370

En Netbeans, para poder crear una ventana modal para nuestra aplicación de Swing, se debe crear un nuevo JFrame Form, y en la línea donde se declara la clase:

public class JModalFrame extends javax.swing.JFrame

cambiarla por:

public class JModalFrame extends javax.swing.JDialog

y en el constructor se debe poner:

setModal(true);

Luego de añadir un área de texto, un checkbox y un botón a la ventana modal, el código para poder retornar valores desde esta ventana es:

    Object[] thoseValues;
   
    public Object[] showDialog()
    {
        return thoseValues;
    }
   
    public JModalFrame()
    {
        setModal(true);
        thoseValues = new Object[2];
        initComponents();
    }

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)                                        
    {                                            
        thoseValues[0] = jCheckBox1.isSelected();
        thoseValues[1] = jTextArea1.getText();
       
        setModal(false);
        this.setVisible(false);
    }                                       
    


Para abrir la ventana modal, se debe añadir el siguiente código en la ventana principal (en mi caso, es la ventana que está declarada como la clase main en las propiedades del proyecto en Netbeans):

    JModalFrame jMod = new JModalFrame();
    jMod.setVisible(true);
    Object[] thosevalues = jMod.showDialog();

    jMod.dispose();


Se pueden recibir cualquier tipo de valores, yo he elegido un array de objetos.


Si se desea que la ventana modal aparezca en la barra de tareas se debe añadir el siugiente código en su constructor:

// http://stackoverflow.com/a/14261194
super(null, java.awt.Dialog.ModalityType.TOOLKIT_MODAL);

lunes, 29 de agosto de 2016

Cómo hacer un Select en un Datatable con campos tipo DateTime

Esta pregunta la hice en StackOverflow en Español, he aquí el resumen:

Tengo un DataTable con dos campos "BirthDay" y "HireDay" del tipo DateTime, y quiero filtrar las filas que correspondan a dos fechas determinadas.
Siguiendo las instrucciones de este enlace armé mi query de la siguiente manera:

DateTime bday = new DateTime(2016, 8, 9);
DateTime hday = new DateTime(2016, 8, 10);

String query =
String.Concat("BirthDay=#", Convert.ToString(bday.Date), "# or HireDay=#", Convert.ToString(bday.Date), "#");
DataRow[] encontrados = miDatatable.Select(query);


Al ejecutar mi aplicación me lanza esta excepción:

Excepción no controlada del tipo 'System.FormatException' en mscorlib.dll
Información adicional: La cadena no se reconoce como DateTime válido. Hay una palabra desconocida al inicio del índice 24.

En cambio, si cambio manualmente el valor de la variable query a:
"BirthDay=#09/08/2016# or HireDay=#10/08/2016#"  
no me tira excepción, pero ya no me devuelve ninguna fila, a pesar de que sí tengo fechas en los campos "BirthDay" y "HireDay" iguales al 9 de agosto del 2016.

La solución me la dio Leandro Tuttini, el formato de fecha debe ser en-US, independientemente de la configuración regional del sistema operativo. La variable query debe armarse de la siguiente forma:

DateTime bday = new DateTime(2016, 8, 9);
DateTime hday = new DateTime(2016, 8, 10);

string query =  string.Format("BirthDay=#{0:MM/dd/yyyy}# or HireDay=#{1:MM/dd/yyyy}#", bday, hday);

DataRow[] encontrados = miDatatable.Select(query);


viernes, 22 de julio de 2016

Cambiando la codificación de un archivo de Python en Python Tools for Visual Studio 2013 Express

Como siempre olvido cómo ponerle la codificación UTF-8 a mis archivos de python he hecho este tutorial. Por defecto el IDE les pone codificación Ansi, sucede que a veces mis comentarios tienen acentos y el intérprete me tira error al ejecutarlos.

1. En la primera línea le ponemos la codificación deseada, en este caso es "# coding=utf-8". La codificación debe ir con el símbolo de numeral para que el intérprete la reconozca:



2. Vamor a Archivo->Guardar como...



3. Elegimos "Guardar con codificación..."



4. Elegimos la codificación "Unicode UTF-8":


De esta forma el intérprete no tirará error al poner comentarios con caracteres internacionales.

martes, 7 de junio de 2016

Detectar si un puerto está abierto en un host específico.

El código original es de Mark Ribaul, yo sólo lo arreglé para testear un puerto específico (probado en Windows 7):


from socket import *
import sys

# http://serverfault.com/a/311580

if __name__ == "__main__":
    fTimeOutSec = 1
    sNetworkAddress = sys.argv[1].split(":")[0]
    aiPort = sys.argv[1].split(":")[1]

    setdefaulttimeout(fTimeOutSec)

    print ("Starting Scan...")
   
    s = socket(AF_INET, SOCK_STREAM)
    result = s.connect_ex((sNetworkAddress, int(aiPort)))

    if (result == 0):
        print ("OPEN: " + sNetworkAddress + ":" + aiPort)

    elif (10035 == result):
        print ("Timeout or inexistent host")
        pass
    else:
        print ("closed: " + sNetworkAddress + ":" + aiPort)

    s.close()

    print ("Scan Completed.")



He puesto el script en un archivo llamado "scan_port.py", y los argumentos que se le pasan son la ip y el puerto separados por dos punto, es decir, de la siguiente manera: "ip:puerto":


Aquí estoy probando con localhost, pero también funciona para ips remotas.

sábado, 21 de mayo de 2016

Error en Visual Studio 2013, no se encontraron exportaciones que coincidieran con la restricción: ContractName

Un día quise abrir mi Visual Studio 2013 Express y me salió una ventana con el siguiente error:

"Error en Visual Studio 2013, no se encontraron exportaciones que coincidieran con la restricción: ContractName".

La solución se encuentra en esta web (link actualizado: https://www.dokry.com/5958 ) pero en mi caso, al usar la versión Express, la carpeta a eliminar está en la ruta "C:\Users\User\AppData\Local\Microsoft\WDExpress\12.0":

sábado, 23 de abril de 2016

Gráfica del Movimiento Browniano unidimensional en Python

El Movimiento Browniano puede considerarse la suma acumulada de una serie de variables aleatorias con distribución normal y media cero. Para aproximar a un Movimiento Browniano continuo, se pueden utilizar "segmentos" (o mejor dicho: sus raíces cuadradas) de un intervalo multiplicado por las variables aleatorias. Las raíces cuadradas resultan de un teorema de convergencia en probabilidad. Esta convergencia se calcula utilizando la función esperanza o media.

El código para generar la gráfica del Movimiento Browniano fue traducido del Matlab al Python a partir del código del capítulo 2 del libro "Stochastic Diferential Equations: Models and Numerics" de Jesper Carlsson, Kyoung-Sook Moon, Anders Szepessy, Raúl Tempone y  Georgios Zouraris. Además, como ejercicio, quise implementar mi propia función de suma acumulada "cumsum". El código resultante es el siguiente:


import numpy as np
import math
import matplotlib.pyplot as plt

def cumsum(lista):
    lista2 = [lista[0]]
    for i in range(1, len(lista)):
        lista2.append(lista[i] + lista2[-1])

    return lista2


N = 1E6
np.random.seed(1337)
A = np.random.normal(0, 1, N-1)
T = 1
dt = 1/(N-1)
t = [c/(N-1) for c in range(0, int(N-1))]
dW = [c*math.sqrt(dt) for c in A]
W = cumsum(dW)

# Aqui se requiere Numpy y Mathplotlib
plt.plot(W)
plt.ylabel('Brownian Motion')
plt.show()

'''
N = 1E6; % number of timesteps
randn('state',0); % initialize random number generator
T = 1; % final time
dt = T/(N-1); % time step
t = 0:dt:T;
dW = sqrt(dt)*randn(1,N-1); % Wiener increments
W = [0 cumsum(dW)]; % Brownian path
LHS = sum(t(1:N-1).*dW);
RHS = T*W(N) - sum(W(1:N-1))*dt;
'''


Para instalar Numpy y Matplotlib se debe bajar el archivo get-pip.py de este enlace. Y se debe ejecutar en la terminal (para Linux) o en el CMD (para Windows) la siguiente instrucción:

python get-pip.py

Si es Linux es mejor poner:

sudo python get-pip.py

La terminal o el CMD deben apuntar a la carpeta donde está el archivo get-pip.py.

Luego se debe instalar numpy y matplotlib. En Linux se ingresa los comandos:

pip install matplotlib
pip install numpy

Si no recuerdo mal, Matplotlib también instala Numpy.

En Windows, como soy muy floja, me descargué el pip-Win e ingresé los respectivos comandos en la caja de texto donde pide el comando:




Éste es el resultado. Estoy usando Python Tools for Visual Studio:




jueves, 17 de marzo de 2016

Calculando el MCD de dos números con el algoritmo de Euclides en Prolog

Esta vez sí estoy usando el algoritmo de Euclides (pero usando restas sucesivas) :D

Blatant Copy/Paste:
La lógica de Prolog es la siguiente: devuelve el valor de retorno en la variable del extremo derecho. La coma es el AND lógico, y el punto y coma el OR lógico. Cada declaración de la función "mcd" equivale a un if.
End of Blatant Copy/Paste

Si el valor en la variable B es 0 ó 1, el algoritmo ignora el valor de A y retorna 0 ó 1 según corresponda. Si no es así, evalúa si A es menor a B, si es así intercambia los valores de A y B, y luego realiza las restas sucesivas como indica el algoritmo. En el algoritmo de Euclides se suele usar un bucle, pero en Prolog se debe utilizar recursividad.

He aquí el código:

mcd(_, 0, 0).
mcd(_, 1, 1).
mcd(A, B, X):- A < B, mcd(B,A,X).
mcd(A, B, X):- N is A - B, N =:= 0, X is B.
mcd(A, B, X):- N is A - B, N =:= B, X is B.
mcd(A, B, X):- N is A-B, N < B, mcd(B, N, X).
mcd(A, B, X):- N is A-B, N > B, mcd(A, N, X).



Estoy usando SWI Prolog 7.2.

miércoles, 10 de febrero de 2016

Visualizar imágenes en Sql Server Management Studio con SSMSBoost

Estaba insertando imágenes a un base de datos en SQL Server 2012 con este código. Luego necesité ver si las imágenes se habían insertado bien. El Sql Server Management Studio no tiene una opción para visualizar imágenes y yo necesitaba algo simple y rápido, de usar y tirar.
Rebuscando en internet hallé un add-on que sí lo permite: el SSMSBoost, el cual tiene una versión Community gratuita que se puede usar para todo, sólo hay que reinstalarla cada tres meses.

Luego de instalarlo, y para poder ver las imágenes, se deben seguir los siguientes pasos:

1. Escoger la tabla con las imágenes y elegir la opción "Visualizar los primeros 1000 registros" haciendo clc derecho (en realidad se debe hacer un select).
2. Hacer click derecho al registro con la imagen que queremos ver, escoger la opción "Visualize as->Settings"


3. En la opción "Picture (any format)", el formato de imagen se coloca png, pues si se deja el valor por defecto (dat) el mspaint no lo va a reconocer:


Esto hace que mspant pueda abrir imágenes png, gif y jpg (no he probado con otros formatos, pero debe funcionar).

4. Luego de presionar el botón "Apply" o "Apply & Close", se escoge la opción "Visualize as->Picture (any format)".

Éste es el resultado:



domingo, 17 de enero de 2016

Implementación del Chatbot Eliza en Prolog

El algoritmo, que permite que Eliza genere una respuesta acorde a las consultas del usuario, se basa en comparar término a término la data ingresada versus una lista de templates con las respuestas predefinidas. Las ideas iniciales para desarrollar este algoritmo fueron obtenidas de [2] y de [3], a partir de estas fuentes se realizó una implementación propia.

El formato de cada template es el siguiente:

template([lista con las palabras del estímulo], [lista con las palabras de la respuesta de Eliza], [lista con las posiciones de las palabras clave en el estímulo empezando de cero]).

Un template de ejemplo tendrá la forma:



Las palabras clave le permiten a Eliza generar una coincidencia para diferentes listas de palabras, tales como “i am sad.” o “i am angry.”. Las palabras claves se reemplazarán en la respuesta en las posiciones donde hay números y no palabras.
 

La función que realiza la comparación es la función “match”. En el estímulo, las palabras clave están marcadas por predicados, mientras que el resto de los términos son atómicos. Cuando la función match detecta un dato no atómico, usando la función de SWI-Prolog “atom”, lo ignora y continúa con la comparación término a término entre la data ingresada y el estímulo. Si se encuentra un template que coincida, devolverá la respuesta correspondiente y la lista de índices. Los índices deben coincidir con las posiciones de los datos no atómicos en el estímulo del template.
 

La función “replace0” se encarga de reemplazar las palabras claves de la data ingresada en las posiciones donde la respuesta del template tiene números. Las palabras clave pueden ser una o más. Para saber qué palabra clave corresponde a qué posición en la respuesta, los números se van incrementando de uno en uno. Si no hay palabras para reemplazar, la lista de índices será una lista vacía.

Esta función llama a las siguientes funciones ya implementadas en SWI-Porlog:

nth0: devuelve el elemento de una lista en una posición dada.

select: reemplaza el valor de un elemento de una lista por otro en función a sus valores.

append: concatena dos listas. En este caso va concatenando las palabras de la respuesta, junto con la palabra reemplazada en la posición donde hay un número, palabra por palabra.
 

La función “replace0” también genera las respuestas a preguntas y consultas del tipo “do you like ...?”, “you are ...” y “do you (verb) ...?”. Los templates correspondientes tienen el siguiente formato:
 


Si la función “replace0” detecta una de las banderas (flags) configuradas, buscará la respuesta correspondiente en las funciones elizaDoes, elizaIs y ElizaLikes, las cuales evalúan los hechos que determinan si Eliza hace, es o le gusta algo. 

El código donde se declaran estos hechos es el siguiente:


El código que le permite al usuario ingresar sus consultas es el siguiente:


La función “readln” convierte las consultas del usuario en una lista. Luego el programa escogerá el primer template de la base del conocimiento, a continuación el estímulo de ese template, y la consulta del usuario (Input), son ingresados a la función “match”. Si el estímulo no coincide con la consulta, Prolog empezará el backtracking, escogiendo el siguiente template y repitiendo la operación. El último template de la base de conocimiento hace que la función “match” retorne verdadero si ninguno de los otros estímulos de los otros templates coincide con la consulta del usuario. Esto evita que se rompa el bucle de Eliza y finalice el programa de forma abrupta. A continuación se llama a la función “replace0”, para luego imprimir la respuesta en la pantalla. Eliza seguirá esperando las consultas del usuario mientras éste no ingrese “bye” o “bye.”.
 

II

Conversando con Eliza


Para interactuar con el programa Eliza, se debe ejecutar el intérprete SWI-Prolog, abrir el archvo eliza_complete.pl y compilarlo. En la consola de SWI-Prolog se deberá ingresar “eliza.” Eliza mostrará un mensaje de bienvenida y esperará por más consultas del usuario. Éstas deben estar en minúsculas y tener un punto al final.

Una conversación de ejemplo es la siguiente:



Eliza da las respuestas en forma de listas de palabras, separadas por comas y entre corchetes. Se mantuvo este formato porque en una aplicación Eliza real, es muy probable que las respuesta halladas requieran un procesamiento posterior.

La aplicación ha sido probada en SWI-Prolog versión 7.2.1. No se ha probado en versiones anteriores. No funcionará en versiones de SWI-Prolog que no tengan implementadas las funciones length, nth0, atom y select.

Esta implementación de Eliza no tiene memoria, es decir, no recuerda las consultas ingresadas y sus respuestas, por lo que la coherencia de la conversación depende del usuario. Por ejemplo, para Eliza es válido ingresar primero la consulta “because you are creepy.” Y luego “i hate you.”.
 

Para ampliar las respuestas de Eliza a más estímulos basta crear más templates con los formatos ya mencionados.


En este programa, la aparente inteligencia de Eliza está en función a la amplitud de su base de conocimientos. Como la coincidencia de las consultas del usuario y los estímulos se realiza término a término, la base de conocimiento de Eliza debe ser bastante grande para producir una conversación coherente, y poder respetar género, número, tiempos verbales, etc. Un programa más completo consideraría toda una lista de palabras clave en lugar de sólo una.

El código completo es (Escrito en Prolog y probado en Swi Prolog v7.2.):


% by: Y3l1nna_Broken_Window:
% la función match permite crear un output para varios inputs.

eliza:-	writeln('Hi, I am Eliza your chatbot,
	please enter your query,
	use only lowercases and a dot at the end:'),
	readln(Input),
	eliza(Input),!.
eliza(Input):- Input == ['bye'],
	writeln('Goodbye. I hope I have helped you.'), !.
eliza(Input):- Input == ['bye', '.'],
	writeln('Goodbye. I hope I have helped you.'), !.
eliza(Input) :-
	template(Stim, Resp, IndStim),
	match(Stim, Input),
	% si he llegado aquí es que he
	% hallado el template correcto:
	replace0(IndStim, Input, 0, Resp, R),
	writeln(R),
	readln(Input1),
	eliza(Input1), !.

% algunos saludos
% debido al backtracking, los templates más específicos deben ir antes
% de los más genéricos. Eso se nota acá:
template([hi, my, name, is, s(_), '.'], ['Hi', 0, 'How', are, you, '?'], [4]).
template([hello, my, name, is, s(_), '.'], ['Hello', 'How', are, you, 0, '?'], [4]).

template([hi, ',', my, name, is, s(_), '.'], ['Hi', 0, 'How', are, you, '?'], [5]).
template([hello, ',', my, name, is, s(_), '.'], ['Hello', 'How', are, you, 0, '?'], [5]).

template([hi, _], ['Hi', 'How', are, you, '?'], []).
template([hello, _], ['Hello', 'How', are, you, '?'], []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

template([i, s(_), i, am, s(_),'.'], [why, do, you, 0, you, are, 1, '?'], [1, 4]).
template([i, s(_), you, '.'], [why, do, you, 0, me ,'?'], [1]).
template([i, am, s(_),'.'], [why, are, you, 0, '?'], [2]).

% pregunta algo que le gusta a eliza
template([do, you, like, s(_), _], [flagLike], [3]).
% pregunta algo que hace eliza
template([do, you, s(_), _], [flagDo], [2]).
% pregunta algo que es eliza
template([you, are, s(_)], [flagIs], [2]).
template([are, you, s(_), '?'], [flagIs], [2]).

template([how, are, you, '?'], [i, am, fine, ',', thanks, for, asking, '.'], []).

template([i, think, _], [well, that, is, just, your, opinion], []).
template([because, _], [that, is, not, a, good, reason, '.'], []).
template([i, have, s(_), with, s(_), '.'], ['You', have, to, deal, with, your, 0, and, your, 1, in, a, mature, way, '.'], [2, 4]).
template([i, s(_),  _], [i, can, recommend, you, a, book, about, that, issue], []).
template([please, s(_), _], ['No', i, can, not, help, ',', i, am, just, a, machine], []). % didn't passed the Turing Test
template([tell, me, a, s(_), _], ['No', i, can, not, ',', i, am, bad, at, that], []). % classic AI problem: una máquina aún no puede contar una historia coherente.

template(_, ['Please', explain, a, little, more, '.'], []). % cuando se ingresa algo que Eliza no tiene en sus templates, esto debe ir al final o eliza responderá a todo con esto.

% Lo que le gusta a eliza : flagLike
elizaLikes(X, R):- likes(X), R = ['Yeah', i, like, X].
elizaLikes(X, R):- \+likes(X), R = ['Nope', i, do, not, like, X].
likes(apples).
likes(ponies).
likes(zombies).

%%%%%%%%%%%%%%%%%%%%%%

% lo que hace eliza: flagDo
elizaDoes(X, R):- does(X), R = ['Yes', i, X, and, i, love, it].
elizaDoes(X, R):- \+does(X), R = ['No', i, do, not, X ,'.', it, is, too, hard, for, me].
does(study).
does(cook).
does(work).

%%%%%%%%%%%%%%%%%
% lo que es eliza: flagIs
elizaIs(X, R):- is0(X), R = ['Yes', i, am, X].
elizaIs(X, R):- \+is0(X), R = ['No', i, am, not, X].
is0(dumb).
is0(weird).
is0(nice).
is0(fine).
is0(happy).
is0(redundant).

%  http://stackoverflow.com/questions/12939425/prolog-access-specific-member-of-list
% magic happens here :D
% lo que hace match es comparar el input y el estímulo término a
% término, ignorando los s(X) en cada template. Si match falla en el
% loop de la función eliza, empezará el backtracking que permite
% recorrer los templates ingresados. match devolverá verdadero si haya
% un estímulo (primer término del template) que coincide con el Input, y
% devolverá la respuesta.
match([],[]).
match([], _):- true.

match([S|Stim],[I|Input]) :-
	atom(S), % si I es un s(X) devuelve falso
	S == I,
	match(Stim, Input),!.

match([S|Stim],[_|Input]) :-
% I es un s(X), lo ignoro y continúo con el resto de la lista
	\+atom(S),
	match(Stim, Input),!.

% esta función es para que se muestre bien en pantalla las respuestas de
% eliza. Además responde a lo que le gusta Eliza y a lo que hace, la
% función select reemplaza el número en la respuesta por la palabra
% clave hallada:
replace0([], _, _, Resp, R):- append(Resp, [], R),!.

% Eliza likes:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagLike,
	elizaLikes(Atom, R).

% Eliza does:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagDo,
	elizaDoes(Atom, R).

% Eliza is:
replace0([I|_], Input, _, Resp, R):-
	nth0(I, Input, Atom),
	nth0(0, Resp, X),
	X == flagIs,
	elizaIs(Atom, R).

replace0([I|Index], Input, N, Resp, R):-
	length(Index, M), M =:= 0,
	nth0(I, Input, Atom),
	select(N, Resp, Atom, R1), append(R1, [], R),!.

replace0([I|Index], Input, N, Resp, R):-
	nth0(I, Input, Atom),
	length(Index, M), M > 0,
	select(N, Resp, Atom, R1),
	N1 is N + 1,
	replace0(Index, Input, N1, R1, R),!.


sábado, 9 de enero de 2016

Listar los archivos en una carpeta y sus subcarpetas de forma recursiva v2

Esta es una versión mejorada de la función listdir_recurd:

import os
import sys
from os import listdir
from os.path import isfile, isdir, join


def listdir_recurd(files_list, root, folder, checked_folders):

    if (folder != root):
        checked_folders.append(folder)

    for f in listdir(folder):
        d = join(folder, f)       

        if isdir(d) and d not in checked_folders:
            listdir_recurd(files_list, root, d, checked_folders)
        else:
            if isfile(d):  # si no hago esto, inserta en la lista el nombre de las carpetas ignoradas
                files_list.append(join(folder, f))

    return files_list


Esta vez, la función devuelve las rutas completas de solamente los archivos que va encontrando, ignorando las carpetas y subcarpetas. Yo necesité esta función para borrar archivos de prueba que generaba otra aplicación, dejando sólo las carpetas vacías:

if __name__ == "__main__":
    # filez = listdir_recurd([], 'D:\test0', 'D:\test0', []) # esto lista todos los archivos
    # filez = listdir_recurd([], 'D:\test', 'D:\test', ['D:\\test\\t1', 'D:\\test\\t2']) # esto omite las carpetas 'D:\\test\\t1' y '
D:\\test\\t2'
    # filez = listdir_recurd([],
'D:\test', 'D:\test', ['D:\\test\\t1']) # esto omite la carpeta 'D:\\test\\t1'
   
    filez = []

    for f in sys.argv[1:]:
         if os.path.exists(f):
            filez += listdir_recurd([], f, f, [])
    

# la línea siguiente es la que hay que temer, borrará todo lo que se haya encontrado
# si por error se ingresa un directorio raíz... lo borrará todo, dejando las carpetas vacías!!
    [os.remove(c) for c in filez if os.path.exists(c)]
    print 'Files Deleted!!'



Como estoy usando Python Tools For Visual Studio, el script se debe setear como Startup File haciéndole click derecho en el explorador de soluciones. Las carpetas cuyos archivos se desean eliminar se ingresan como:


Hay que tener cuidado al borrar archivos con este método ya que no van a la papelera de reciclaje.