PDA

Ver la Versión Completa : Sacar números de cadenas de caracteres.


McK
30-11-2010, 14:46:53
Parece una pregunta un tanto tonta, ya que con 2 bucles for y recorriéndola se puede hacer, pero me preguntaba si pudiera existir alguna función en delphi que sea más efectiva y menos medieval para hacerlo.

Como ejemplo, lo que quiero hacer es sacar los numeros que vienen detras de unas letras concretas en una cadena de caracteres:

DHS274HGL23JH41234HGL412YG

Las letras concretas aquí (p.e.) serían HGL. Por lo que los números que en este caso necesitaría sacar y guardar son el 23 y el 412.

Un saludo y gracias!

marcoszorrilla
30-11-2010, 15:06:51
Si mantiene la posición puedes utilizar Copy

xx:=Copy(Cadena,4,3);


Un Saludo.

Neftali [Germán.Estévez]
30-11-2010, 17:38:25
Pues a mi sólo se me ocurre con 2 bucles.
El primero para encontrar y recorrer las ocurrencias de la cadena buscada (suponiendo que hay varias) y el segundo para extraer los números antes de la csiguiente letra (que por lo que veo pueden tener longitud indeterminada).

ecfisa
30-11-2010, 19:09:08
Hola McK.

Estoy de acuerdo con Neftali, se necesitan dos ciclos.

Pero mas eficiente que usar dos for es:

function ExtractNum(Sub, Str: string): TStrings;
var
i, p: Integer;
begin
Result:= TStringList.Create;
p:= 1;
while p <> 0 do
begin
p:= Pos(Sub, Str);
if p > 0 then
begin
Inc(p, Length(Sub));
i:= 1;
while Str[p + i] in ['0'..'9'] do Inc(i);
Result.Add(Copy(Str, p, i));
Inc(p, i);
Str:= Copy(Str, p, MaxInt);
end;
end;
end;


Ejemplo de llamada:

procedure TForm1.Button1Click(Sender: TObject);
const
Cadena = 'HGL44DHS274HGL23JHGL41234HGL412YGHGL555XADSF1AHG12HGL999';
begin
Memo1.Lines:= ExtractNum('HGL', Cadena);
end;


Saludos. :)

Estifmauin
01-12-2010, 00:05:25
Otro enfoque, más legible, pero creo que menos eficiente:

function SoloNumeros(s:string):string;
var
n :integer;
begin
result:='';
n:=1;
while (n <= Length(s))
and (s[n] in ['0'..'9']) do begin
result:=result+s[n];
Inc(n);
end;
end;

function ExtraerNumeros(cadena, prefijo :string) :TStrings;
var
i :integer;
begin
result:=TStringList.Create;
result.CommaText:=StringReplace(cadena,prefijo,',',[rfReplaceAll]);
for i:=result.Count -1 downto 0 do begin
result[i]:=SoloNumeros(result[i]);
if result[i] = '' then result.Delete(i);
end;
end;

Para llamarlo:
procedure TForm1.Button1Click(Sender: TObject);
begin
memo1.Lines:=ExtraerNumeros('HGL44DHS274HGL23JHGL41234HGL412YGHGL555XADSF1AHG12HGL999','HGL');
end;

Es más legible, pero insisto en que menos eficiente, y requiere uses StrUtils

McK
01-12-2010, 13:44:41
Perfecto, gracias a todos. Aunque no haya una instrucción de Delphi eso está bastante simplificado. Yo lo tenía algo peor implementado.

Un saludo!

roman
01-12-2010, 16:23:58
Desafortunadamente delphi no cuenta con un manejo de expresiones regulares, al menos delphi 7. Por ejemplo, en PHP este problema se resuelve así:


<?php
$s = 'DHS274HGL23JH41234HGL412YG';
preg_match_all('/HGL([0-9]+)/', $s, $matches);
var_dump($matches[1]);
?>


// Saludos

McK
02-12-2010, 11:16:52
Hola McK.

Estoy de acuerdo con Neftali, se necesitan dos ciclos.

Pero mas eficiente que usar dos for es:

Código Delphi [-]

function ExtractNum(Sub, Str: string): TStrings;
var
i, p: Integer;
begin
Result:= TStringList.Create;
p:= 1;
while p <> 0 do
begin
p:= Pos(Sub, Str);
if p > 0 then
begin
Inc(p, Length(Sub));
i:= 1;
while Str[p + i] in ['0'..'9'] do Inc(i);
Result.Add(Copy(Str, p, i));
Inc(p, i);
Str:= Copy(Str, p, MaxInt);
end;
end;
end;


Ejemplo de llamada:

Código Delphi [-]

procedure TForm1.Button1Click(Sender: TObject);
const
Cadena = 'HGL44DHS274HGL23JHGL41234HGL412YGHGL555XADSF1AHG12HGL999';
begin
Memo1.Lines:= ExtractNum('HGL', Cadena);
end;


Saludos.

No me está funcionando tu código amigo. Siempre me detecta el primer substring por lo que se queda en un bucle infinito..

ecfisa
02-12-2010, 11:55:45
No me está funcionando tu código amigo. Siempre me detecta el primer substring por lo que se queda en un bucle infinito..

Mi amigo, acabo de copiar y pegar el código de la función y funciona correctamente.

Te adjunto la prueba:

function ExtractNum(Sub, Str: string): TStrings;
var
i, p: Integer;
begin
Result:= TStringList.Create;
p:= 1;
while p <> 0 do
begin
p:= Pos(Sub, Str);
if p > 0 then
begin
Inc(p, Length(Sub));
i:= 1;
while Str[p + i] in ['0'..'9'] do Inc(i);
Result.Add(Copy(Str, p, i));
Inc(p, i);
Str:= Copy(Str, p, MaxInt);
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
const
Cadena = 'XX979ASDB12XX77DT12ADSXX99199ABCXX8838xx33'; // Con la del ejemplo anterior también funciona OK
begin
Memo1.Lines:= ExtractNum('xx', Cadena); // muestra 33
ShowMessage('FIN');
Memo1.Lines:= ExtractNum('', Cadena); // no muestra nada
ShowMessage('FIN');
Memo1.Lines:= ExtractNum('XX', Cadena); // muestra 979, 77, 99199, 8838
ShowMessage('FIN');
Memo1.Lines:= ExtractNum('xy', Cadena); // no muestra nada
ShowMessage('FIN');
end;


¿ Podrías poner un ejemplo que te dé el ciclo infinito ? Así puedo evaluarlo.

Saludos. :)

McK
02-12-2010, 23:27:27
Mi amigo, acabo de copiar y pegar el código de la función y funciona correctamente.

Te adjunto la prueba:
Código Delphi [-] (http://www.clubdelphi.com/foros/#)function ExtractNum(Sub, Str: string): TStrings; var i, p: Integer; begin Result:= TStringList.Create; p:= 1; while p <> 0 do begin p:= Pos(Sub, Str); if p > 0 then begin Inc(p, Length(Sub)); i:= 1; while Str[p + i] in ['0'..'9'] do Inc(i); Result.Add(Copy(Str, p, i)); Inc(p, i); Str:= Copy(Str, p, MaxInt); end; end; end; procedure TForm1.Button1Click(Sender: TObject); const Cadena = 'XX979ASDB12XX77DT12ADSXX99199ABCXX8838xx33'; // Con la del ejemplo anterior también funciona OK begin Memo1.Lines:= ExtractNum('xx', Cadena); // muestra 33 ShowMessage('FIN'); Memo1.Lines:= ExtractNum('', Cadena); // no muestra nada ShowMessage('FIN'); Memo1.Lines:= ExtractNum('XX', Cadena); // muestra 979, 77, 99199, 8838 ShowMessage('FIN'); Memo1.Lines:= ExtractNum('xy', Cadena); // no muestra nada ShowMessage('FIN'); end;


¿ Podrías poner un ejemplo que te dé el ciclo infinito ? Así puedo evaluarlo.

Saludos. :)

Gracias compañero ya lo he arreglado con un auxiliar. No sé porque mi variable p no pasaba de la primera substring pero es tu código tal cual... con mi aux lo que hago es copiarme la cadena y a la que va encontrando las substrings las va borrando, por lo que a la fuerza tiene que coger la siguiente. Tengo Delphi 7, quizas por la versión.... :confused:

ecfisa
02-12-2010, 23:40:26
Gracias compañero ya lo he arreglado con un auxiliar. No sé porque mi variable p no pasaba de la primera substring pero es tu código tal cual... con mi aux lo que hago es copiarme la cadena y a la que va encontrando las substrings las va borrando, por lo que a la fuerza tiene que coger la siguiente. Tengo Delphi 7, quizas por la versión.... :confused:

Un detalle McK, si bien no me pasó lo del bucle infinito, descubrí un fallo en el código.

En la cadena anterior:

XX979ASDB12XX77DT12ADSXX99199ABCXX8838xx33

Si usas: ExtractNum('AS', Cadena) -> te devuelve: 'B'.

Es por que inicialicé mal el contador de ocurrencias numéricas y si o sí me pone un caracter aunque no sea un número.
Hay que inicializar distinto a 'i':

...
begin
Inc(p, Length(Sub));
// i:= 1; BORRAR LINEA
i:= 0; // NUEVA LINEA
...



Un saludo. :)

mamcx
03-12-2010, 04:02:10
Desafortunadamente delphi no cuenta con un manejo de expresiones regulares

En la version actual si. Ademas que agregarle la libreria es cosa de niños.

McK
03-12-2010, 09:01:02
Un detalle McK, si bien no me pasó lo del bucle infinito, descubrí un fallo en el código.

En la cadena anterior:

Si usas: ExtractNum('AS', Cadena) -> te devuelve: 'B'.

Es por que inicialicé mal el contador de ocurrencias numéricas y si o sí me pone un caracter aunque no sea un número.
Hay que inicializar distinto a 'i':
Código Delphi [-] (http://www.clubdelphi.com/foros/#)... begin Inc(p, Length(Sub)); // i:= 1; BORRAR LINEA i:= 0; // NUEVA LINEA ...



Un saludo. :)

Vaaaaale ya sé lo que pasaba!!! Que despiste.... lo de i:= 0 ya me dí cuenta cuando lo depuraba..

function ExtractNum(Sub, Str: string): TStrings;
var
i, p: Integer;
begin
Result:= TStringList.Create;
p:= 1;
while p <> 0 do
begin
p:= Pos(Sub, Str);
if p > 0 then
begin
Inc(p, Length(Sub));
i:= 1;
while Str[p + i] in ['0'..'9'] do Inc(i);
Result.Add(Copy(Str, p, i));
Inc(p, i);
Str:= Copy(Str, p, MaxInt); // Esta línea no la había metido!!!
end; // De todas formas en mi procedure he metido esto tal cual sin crear ninguna función
end; // y por no modificar mi cadena por eso he utilizado el auxiliar.
end;
Mil gracias y perdona por el mareo!!
Saludos :)

roman
03-12-2010, 16:54:02
En la version actual si. Ademas que agregarle la libreria es cosa de niños.

Entonces, en la versión actual, definitivamente se impone el uso de expresiones regulares para resolver problemas como éste

También tienes razón en que puede usarse una librería (biblioteca por si Al lee esto) externa, pero cuando se requiere para apenas un uso puntual, como que se siente que se está matando una pulga a cañonazos :)

// Saludos

Delfino
03-12-2010, 21:24:31
Desafortunadamente delphi no cuenta con un manejo de expresiones regulares, al menos delphi 7.
Ya lo tiene en Delphi XE, y aqui (http://www.andreanolanusse.com/blogen/using-regular-expressions-to-validate-ip-address-with-delphi-xe/) un ejemplo..