elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Trabajando con las ramas de git (tercera parte)


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  [C]isNumeric (VB6 a C)
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: [C]isNumeric (VB6 a C)  (Leído 4,728 veces)
BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
[C]isNumeric (VB6 a C)
« en: 16 Agosto 2011, 22:45 pm »

.
Se trabajan las funciones a nivel Bit, ambas funciones son mas rapidas que la nativa en vb6.

Funcion en VB6

Codigos para descargar...
Archivos Fuente dll, y Compilados



La funcion isnumeric_Black esta en VB6, es la version en vb6 de la que esta aqui...

Código:

http://foro.elhacker.net/programacion_visual_basic/reto_reemplazo_de_funcion_isnumeric-t336067.0.html;msg1652210#msg1652210

main.cpp


y aqui les dejo la traduccion en C (Las funciones IsNumericA y IsNumericW estan configuradas para trabajar con las Strings de VB6)

Código
  1.  
  2. #include "main.h"
  3.  
  4. /**
  5.     @Autor          BlackZeroX
  6.     @Web            http://infrangelux.sytes.net/blog/
  7.     @Reference      http://foro.elhacker.net/programacion_visual_basic/reto_reemplazo_de_funcion_isnumeric-t336067.0.html;msg1652210#msg1652210
  8.     @Description    Libreria para verificar si una Cadena de texto ANSI/UNICODE es numerica con los siguientes formatos:
  9.                     * ###e[+/-]###  {+/-646.45e+546,45}.
  10.                     * ###d[+/-]###  {+/-646.45d+546,45}.
  11.                     * Base 16       {&H4561abcdef}.
  12.                     * Base 10       {+/-456,541.456,545}.
  13.     @Returns        0 si la cadena no contiene ningun formato.
  14.                     1 si la cadena pertenece a algun tipo de formato numerico.
  15. **/
  16.  
  17. #define PUNTO_DECIMAL     0x10000
  18. #define SIGNO_SRC         0x20000
  19. #define NUMBER_HEX        0x40000
  20. #define NUMBER_HEX_ZERO   0x80000
  21. #define NUMBER_HEX_FLAGS  (NUMBER_HEX | NUMBER_HEX_ZERO)
  22. #define NUMBER_POW        0x100000
  23. #define NUMBER_POW_FINISH 0x200000
  24. #define NUMBER_POW_FLAGS  (NUMBER_POW | NUMBER_POW_FINISH)
  25. #define NUMBER_OF_OK      0x400000
  26. #define NUMBER_OF_FINISH  0x800000
  27. #define NUMBER_OF_FLAGS   (NUMBER_OF_OK | NUMBER_OF_FINISH)
  28.  
  29. DLL_EXPORT int __stdcall IsNumericA (char *pStr) { return pStr ? IsNumericEx(pStr, *((int*)(pStr - 0x4)), 1): 0; }
  30. DLL_EXPORT int __stdcall IsNumericW (char *pStr) { return pStr ? IsNumericEx(pStr, *((int*)(pStr - 0x4)), 2): 0; }
  31.  
  32. int IsNumericEx (char *pStr, size_t uiLn, int iStep) {
  33. unsigned int i       = 0x0,  //  For()
  34.             iData   = 0x0;  //  Xor, Switcher, Contador (QWord).
  35.  
  36.    if (!pStr || !uiLn)
  37.        return 0;
  38.  
  39.    for (i = 0; i < uiLn; i += iStep) {
  40.        if ((iData & NUMBER_HEX) == NUMBER_HEX) {
  41.            if (((*pStr >= 0x30) && (*pStr <= 0x39)) ||
  42.               ((*pStr >= 0x61) && (*pStr <= 0x66)) ||
  43.               ((*pStr >= 0x41) && (*pStr <= 0x46))) {  //  Numeros Hexadecimales
  44.                if ((iData & NUMBER_OF_FLAGS) == 0x0)   //  Ceros a la izquierda
  45.                    iData |= (*pStr == 0x30) ? NUMBER_HEX_ZERO : NUMBER_OF_OK;
  46.  
  47.                switch (iData & NUMBER_OF_FLAGS) {
  48.                    case NUMBER_OF_OK:
  49.                        iData++;
  50.                        if ((iData & 0xFF) == 0x11)
  51.                            return 0;   //  QWord (Max Double)
  52.                        iData |= NUMBER_OF_OK;
  53.                        if ((iData | NUMBER_HEX_FLAGS) == NUMBER_HEX_FLAGS)
  54.                            iData ^= NUMBER_HEX_ZERO;
  55.                        break;
  56.  
  57.                    case NUMBER_OF_FINISH:
  58.                    case NUMBER_OF_FLAGS:
  59.                        return 0;
  60.                        break;
  61.               }
  62.            } else {
  63.                switch (*pStr) {
  64.                    case 0x9:
  65.                    case 0xA:
  66.                    case 0xB:
  67.                    case 0xC:
  68.                    case 0xD:
  69.                    case 0x24:
  70.                    case 0x20:
  71.                    case 0xA0:  //   Espacios en Blanco
  72.                        if ((iData | NUMBER_HEX_FLAGS) == NUMBER_HEX_FLAGS)
  73.                            iData = ((iData ^ NUMBER_HEX_ZERO) | NUMBER_OF_OK);
  74.                        if ((iData & NUMBER_OF_FLAGS) == NUMBER_OF_OK)
  75.                            iData |= NUMBER_OF_FINISH;
  76.                        break;
  77.  
  78.                    case 0x0:    //  NULL Indica que se termina la cadena.
  79.                        if ((iData & NUMBER_OF_FLAGS) == NUMBER_OF_FINISH)
  80.                            return 0;
  81.                        i = uiLn; //  Exit For.
  82.                        break;
  83.  
  84.                    default:
  85.                        return 0;
  86.                        break;
  87.                }
  88.            }
  89.        } else {
  90.            if ((*pStr >= 0x30) && (*pStr <= 0x39)) {
  91.                iData |= NUMBER_OF_OK;
  92.                if ((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH)
  93.                    return 0;
  94.                if ((iData & NUMBER_POW_FLAGS) == NUMBER_POW)
  95.                    iData |= NUMBER_POW_FINISH;
  96.  
  97.            } else {
  98.                switch ((int)*pStr) {
  99.                    case 0x0:    //  NULL Indica que se termina la cadena.
  100.                        if ((iData & NUMBER_POW_FLAGS) == NUMBER_POW)
  101.                            return 0;
  102.                        i = uiLn;    //  Exit For.
  103.                        break;
  104.  
  105.                    case 0x2E:   //  "."  Solo 1
  106.                        if (((iData & NUMBER_POW_FLAGS) == NUMBER_POW) ||
  107.                           ((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH) ||
  108.                           ((iData & PUNTO_DECIMAL) == PUNTO_DECIMAL))
  109.                            return 0;
  110.                        iData |= PUNTO_DECIMAL;
  111.                        break;
  112.  
  113.                    case 0x2B:
  114.                    case 0x2D: //  "+|-" Solo 1
  115.                        if ((iData & NUMBER_POW_FLAGS) == NUMBER_POW)
  116.                            iData |= NUMBER_POW_FINISH;
  117.  
  118.                        else
  119.                            if (((iData & NUMBER_OF_OK) == NUMBER_OF_OK) ||
  120.                               ((iData & PUNTO_DECIMAL) == PUNTO_DECIMAL) ||
  121.                               ((iData & SIGNO_SRC) == SIGNO_SRC))
  122.                            return 0;
  123.  
  124.                        if ((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH)
  125.                            return 0;
  126.  
  127.                        iData |= SIGNO_SRC;
  128.                        break;
  129.  
  130.                    case 0x2C:
  131.                        if ( !((iData & NUMBER_OF_OK) == NUMBER_OF_OK) ||
  132.                              ((iData & NUMBER_POW_FLAGS) == NUMBER_POW))
  133.                            return 0;
  134.                        break;
  135.  
  136.                    case 0x9:
  137.                    case 0xA:
  138.                    case 0xB:
  139.                    case 0xC:
  140.                    case 0xD:
  141.                    case 0x24:  //  Solo se permiten al inicio de un Numero (Espacios en Blanco).
  142.                        if (((iData & PUNTO_DECIMAL) == PUNTO_DECIMAL) ||
  143.                           ((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH) ||
  144.                           ((iData & NUMBER_OF_OK) == NUMBER_OF_OK) ||
  145.                           ((iData & NUMBER_POW_FLAGS) == NUMBER_POW))
  146.                            return 0;
  147.                        break;
  148.  
  149.                    case 0xA0:
  150.                    case 0x20: //  Se permiten al Inicio/final de un numero.
  151.                        if ((iData & NUMBER_OF_OK) == NUMBER_OF_OK)
  152.                            iData |= NUMBER_OF_FINISH;
  153.                        else
  154.                            if (((iData & PUNTO_DECIMAL) == PUNTO_DECIMAL) ||
  155.                               ((iData & NUMBER_POW_FLAGS) == NUMBER_POW))
  156.                                return 0;
  157.                        break;
  158.  
  159.                    case 0x26:   //  Es un Numero Hexadecimal
  160.                        if (((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH) ||
  161.                           ((iData & NUMBER_OF_OK) == NUMBER_OF_OK) ||
  162.                           ((iData & SIGNO_SRC) == SIGNO_SRC) ||
  163.                           ((iData & PUNTO_DECIMAL) == PUNTO_DECIMAL) ||
  164.                           ((iData & NUMBER_POW_FLAGS) == NUMBER_POW))
  165.                            return 0;
  166.  
  167.                        pStr += iStep;
  168.  
  169.                        if ((*pStr == 0x48) || (*pStr == 0x68)) {
  170.                            iData |= NUMBER_HEX;
  171.                            iData ^= 0xFF000000;
  172.                            i += iStep;
  173.                        } else {
  174.                            pStr -= iStep;
  175.                        }
  176.                        break;
  177.  
  178.                    case 0x44:
  179.                    case 0x45:
  180.                    case 0x64:
  181.                    case 0x65:     //  Numeros en Formato ###e-###, ###e+###
  182.                        if (((iData & NUMBER_OF_FINISH) == NUMBER_OF_FINISH) ||
  183.                           ((iData & NUMBER_POW) == NUMBER_POW))
  184.                            return 0;
  185.                        if ((iData & NUMBER_OF_OK) == NUMBER_OF_OK) {
  186.                            iData |= NUMBER_POW;
  187.                            if ((iData & SIGNO_SRC) == SIGNO_SRC)
  188.                                iData ^= SIGNO_SRC; //  Permitimos nuevamente los signos "+" y "-".
  189.                        } else {
  190.                            return 0;
  191.                        }
  192.                        break;
  193.  
  194.                    default:
  195.                        return 0;
  196.                        break;
  197.  
  198.                }   //  switch()
  199.            }   //  if()
  200.        }   //  if()
  201.        pStr += iStep;
  202.    }   //  For()
  203.  
  204.    switch (iData & NUMBER_OF_FLAGS) {
  205.        case NUMBER_OF_OK:
  206.        case NUMBER_OF_FLAGS:
  207.            return 1;
  208.            break;
  209.  
  210.        default:
  211.            switch (iData & NUMBER_HEX_FLAGS) {
  212.                case NUMBER_HEX_FLAGS:
  213.                    return 1;
  214.                    break;
  215.            }
  216.    }
  217.  
  218.    return 0;
  219. }
  220.  
  221.  

main.h
Código
  1.  
  2. #ifndef __MAIN_H__
  3. #define __MAIN_H__
  4.  
  5. #include <windows.h>
  6.  
  7. #ifdef BUILD_DLL
  8.    #define DLL_EXPORT __declspec(dllexport)
  9. #else
  10.    #define DLL_EXPORT __declspec(dllimport)
  11. #endif
  12.  
  13. #ifdef __cplusplus
  14. extern "C"
  15. {
  16. #endif
  17.  
  18. DLL_EXPORT int __stdcall IsNumericA (char*);
  19. DLL_EXPORT int __stdcall IsNumericW (char*);
  20. int IsNumericEx (char *pStr, size_t uiLn, int iStep);
  21.  
  22. #ifdef __cplusplus
  23. }
  24. #endif
  25.  
  26. #endif // __MAIN_H__
  27.  
  28.  

Dulces Lunas!¡.


« Última modificación: 20 Agosto 2011, 03:28 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: [C]isNumeric (VB6 a C)
« Respuesta #1 en: 19 Agosto 2011, 17:55 pm »

En el caso de C y si la intención es validar solo tipos enteros se puede utilizar la función strtol (prototipo en <stdlib.h>) dejando a esta la mayor parte del trabajo. Por ejemplo:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4. #include <limits.h>
  5. #include <errno.h>
  6.  
  7. #define NUM_CHARS 256
  8.  
  9. int validar_int(char const *linea, int *num);
  10.  
  11. int main(void)
  12. {
  13.   char linea[NUM_CHARS];
  14.   int num;
  15.  
  16.   printf("Introduce un numero entero (signed int): ");
  17.   fflush(stdout);
  18.   if (fgets(linea, NUM_CHARS, stdin) == NULL)
  19.      return EXIT_FAILURE;
  20.  
  21.   if (validar_int(linea, &num))
  22.      printf("OK. El numero es %d\n", num);
  23.   else
  24.      puts("Error!");
  25.  
  26.   return EXIT_SUCCESS;
  27. }
  28.  
  29.  
  30. int validar_int(char const *linea, int *num)
  31. {
  32.   char *ch;
  33.   long res;
  34.  
  35.   /* Descartamos el ultimo error y tratamos de convertir la linea */
  36.   errno = 0;
  37.   res = strtol(linea, &ch, 0);
  38.  
  39.   /* A continuacion verificamos ... */
  40.  
  41.   /* ... si al menos un caracter pudo convertirse con exito */
  42.   if (res == 0 && ch == linea)
  43.      return 0;
  44.  
  45.   /* ... si el numero esta en el rango valido (signed long) */
  46.   if (errno == ERANGE && (res == LONG_MAX || res == LONG_MIN))
  47.      return 0;
  48.  
  49.   /* ... si el resto de la linea es espacio blanco */
  50.   while (isspace(*ch))
  51.      ch++;
  52.   if (*ch != '\0')
  53.      return 0;
  54.  
  55.   /* ... si el numero esta en el rango valido (signed int) */
  56.   if (res > INT_MAX || res < INT_MIN)
  57.      return 0;
  58.  
  59.   /* Si todo se cumple el numero introducido es valido */
  60.   *num = res;
  61.  
  62.   return 1;
  63. }

Para números de tipo flotante se puede tomar una aproximación similar utilizando strtod (prototipo tambien en <stdlib.h>).

Un saludo


En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
someRandomCode

Desconectado Desconectado

Mensajes: 250



Ver Perfil
Re: [C]isNumeric (VB6 a C)
« Respuesta #2 en: 19 Agosto 2011, 20:36 pm »

O, existen todos estos:
int isalnum(int c);
int isalpha(int c);
int isascii(int c);
int isblank(int c);
int isdigit(int c);
int isxdigit(int c);

Que los podes encontrar en ctype.h

Dejo esos, y si lo que queres es validar una cadena:
Código:
int isnumeric(char * cadena) {
  while(*cadena)  { // Mismo que decir *cadena distinto de NULL o distinto de '\0'
    if(!isdigit(*cadena)) // Cuando lo que busquemos en la cadena NO sea un digito
      return 0; // Retornamoso 0 -> para decir falso, recordar que C no tiene tipo boolean, salvo que usen alguna API como la de Windows que tiene el tipo BOOL pero es una estructura y los valores se los interpreta como enteros al fin y al cabo
    cadena++; // Nos movemos al proximo en la cadena (incrementamos la direccion del puntero al proximo elemento)
  }
  return 1; // Si llegue hasta aca, es porque no me encontre con ningun caracter no-numerico, retorno 1-> pa' decir verdadero
}
En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [C]isNumeric (VB6 a C)
« Respuesta #3 en: 19 Agosto 2011, 23:51 pm »

@rir3760.
@someRandomCode

Las funciones son buenas pero ineficientes, el caso es detectar una cadena con espacios validos y con formato valido, sin decir que debe ser RAPIDA:

* Numeros Enteros.
* Numeros con Punto decimal.
* Numeros con formato Hexadecimal de tamaño QWord.
* Numeros en NOTACION Cientifica.
* Las comas funcionan como separadores numericos de miles.
* En TODOS los casos anterior pueden ser tanto positivos como negativos.

Pasen a el post citado y veran una serie de Strings con una variedad amplia de formatos a probar en las funciones, ya que las vuestras se quedan a medias aun cuando son en C no superan en lo abosuluto ni siquiera a la que hice en vb6.

Dulces Lunas!¡.
« Última modificación: 20 Agosto 2011, 00:00 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
someRandomCode

Desconectado Desconectado

Mensajes: 250



Ver Perfil
Re: [C]isNumeric (VB6 a C)
« Respuesta #4 en: 20 Agosto 2011, 01:16 am »

Hmm, no se, podrias aportar tiempos para las mismas?
No obstante, lo que propusiste tambien es una funcion, de tamaño un poco grandota.
Las funciones pueden ser ineficientes por todo lo que acarrea su invocacion, pero no te olvides que vivimos en una era donde un call o un ret no se consumen tantos ciclos como para morirse...

Ademas de que Visual Basic (aclaremos la version, ademas, porque varia) es bastante lento por tener que cargar de todo. Ubound y Lbound por ejemplo son funciones. Que estas usando ahi adentro.

Lo interesante seria que agarres y hagas un Time (GetSystemTimeMillis) antes y despues, y probeas un test case para demostrar que es cierto.

En general es buena idea no reinvetar la rueda, y tratar de usar cosas que ya han dado vueltas optimizadas por alguna gente que tiene el ojo en el tema.

Ojo, no estoy desmereciendo ni diciendo nada pero me da pereza bajarme VB, y hacer la prueba yo..
En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [C]isNumeric (VB6 a C)
« Respuesta #5 en: 20 Agosto 2011, 02:40 am »

.
Los test (tiempos) ya estan en la url... esta funcion trabaja a nivel Bit y es una traduccion mera de la que esta en vb6, tiene un tiempo de diferencia de 5-10 msc respectivamente a 1000 ciclos con varias strings a probar, lo unico en lo que radica esta verison con la de vb6, es que en VB6 no puedo trabajar directamente con cada caracter, y en esta si, en la de vb6 use RtlMoveMemory para tal cosa.

A esta version le saque dos variantes segun las string a probar es decir ANSI y UNICODE.

La funcion es grandota pero trabaja tan rapido como lo permiten las operaciones a nivel Bit y por punteros sin usar tanta memoria para las variables booleanas, en la de vb6 tomo partido de la longitud INT32 como es nativo de vb6 y de igual manera sacandole partido a las operaciones a nivel Bit...

En el caso de reinventar la rueda:
 * Es cierto, pero si la funcion es lenta... o no cumple las espectativas, o mejor aun si no la puedes editar mejor recrearla, en este caso salio una funcion mas optimizada que la de vb6 y a su vez mas rapida, creo que reinventar la rueda en ocasiones tiene sus ventajas.

No soy el unico que hace este tipo de cosas: VBSpeed

Nota: No use en ningun momento LBound ni Ubound ya que no ocupo ningun tipo de array, estas funciones trabajan directamente con la estructura del SafeArray de un Array como es obvio...

Dulces Lunas!¡.
« Última modificación: 20 Agosto 2011, 03:02 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [C]isNumeric (VB6 a C)
« Respuesta #6 en: 20 Agosto 2011, 02:50 am »

.
Los tiempos se han calculado con las APIS:

@kernel32
QueryPerformanceCounter
QueryPerformanceFrequency

Dulces Lunas!¡.
En línea

The Dark Shadow is my passion.
someRandomCode

Desconectado Desconectado

Mensajes: 250



Ver Perfil
Re: [C]isNumeric (VB6 a C)
« Respuesta #7 en: 20 Agosto 2011, 02:55 am »

Seria interesante que alguien los postee para no tener que hacerlo(como en realidad dije antes), je igual bien que si hicieron las pruebas, quede.
Y saber bien la metodologia que usaron para medirlo, pero esta bien, si usted lo dice felicitaciones atrasadas (porque hasta donde veo, es de hace raaato el thread :) )

En línea

BlackZeroX
Wiki

Desconectado Desconectado

Mensajes: 3.158


I'Love...!¡.


Ver Perfil WWW
Re: [C]isNumeric (VB6 a C)
« Respuesta #8 en: 20 Agosto 2011, 03:21 am »

.
No te molesta si te dejo el EXE?, igual pongo una captura.

Archivos Fuente dll, y Compilados



La funcion isnumeric_Black esta en VB6, es la version en vb6 de la que esta aqui...

Dulces Lunas!¡.
« Última modificación: 20 Agosto 2011, 03:28 am por BlackZeroX▓▓▒▒░░ » En línea

The Dark Shadow is my passion.
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
[RETO] Reemplazo de Funcion IsNumeric « 1 2 3 4 5 »
Programación Visual Basic
79137913 46 18,871 Último mensaje 20 Agosto 2011, 03:29 am
por BlackZeroX
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines