Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Quitar dos espacios en cadena dejar uno (https://www.clubdelphi.com/foros/showthread.php?t=89182)

sonjeux 12-10-2015 05:43:27

Quitar dos espacios en cadena dejar uno
 
Saludos, quisiera saber como puedo hacer para limpiar una cadena que tiene muchos espacios, o sea dejar solo uno

Una cadena como esta

Código:

'70224637            444      54666 4      4512              4  5 4 50 '
que quede como esta

Código:

'70224637 444 54666 4 4512 4 5 4 50 '
con un solo espacio, gracias por su tiempo

Nasca 12-10-2015 12:23:12

Yo tengo esto:

Código Delphi [-]
function BorrarMultiEspacios(valor: string): string;
 begin
   repeat
       valor := StringReplace(valor,'  ',' ',[rfReplaceAll]);
   until
       pos('  ',valor) = 0 ;
   Result := valor;    
 end;

Ni idea de si es lo más optimo. De hecho ni recuerdo si es mio o lo copié de algún lado.
Otra opción en:
http://texthandler.com/?module=remov..._spaces_delphi
Aunque no creo que sea mucho mas eficiente.

O adaptar este código de c#, bastante similar al mío:

Código:

    while (text.IndexOf("  ") != -1)
    {
        text = text.Replace("  ", " ");
    }
    return text;

Aunque hace básicamente lo mismo y no creo que sea mucho más eficiente que el primero.

roman 12-10-2015 19:13:27

A ver si ésta (recorre una sóla vez la cadena):

Código Delphi [-]
function ComprimeEspacios(S: String): String;
var
  I: Integer;

begin
  I := 1;

  while I <= Length(S) do
  begin
    while (I <= Length(S)) and (S[i] <> ' ') do
      Inc(I);

    Inc(I);

    while (I <= Length(S)) and (S[i] = ' ') do
      Delete(S, I, 1);

    Inc(I);
  end;

  Result := S;
end;

// Saludos

ecfisa 12-10-2015 21:49:16

Hola.

Otra opción:
Código Delphi [-]
function DeleteExtraSpaces(str: string): string;
var
  i: integer;
begin
  for i := 1 to Length(str)-1 do
    while (str[i] = ' ') and (str[i+1] = ' ') do
      Delete(str, i+1, 1);
  Result := str;
end;

Saludos :)

sonjeux 13-10-2015 17:12:00

Muchas gracias a todos, me sirvio un moton

mamcx 13-10-2015 23:03:12

Esa es una forma destructiva (borrando). Otra manera es construir una nueva cadena, y cuando hay un espacio agregar el primero e ignorar los que vengan.

ecfisa 14-10-2015 02:13:56

Cita:

Empezado por mamcx (Mensaje 497889)
Esa es una forma destructiva (borrando). Otra manera es construir una nueva cadena, y cuando hay un espacio agregar el primero e ignorar los que vengan.

Si, tenes razón... y con seguridad es mas eficiente al omitir la llamada a la función Delete:

Código Delphi [-]
function IgnoreExtraSpaces(str: string): string;
var
  i: integer;
begin
  SetLength(str, Length(str)+1);
  for i := 1 to Length(str)-1 do
    if (str[i] <> ' ') or (str[i+1] <> ' ') then
      Result := Result + str[i];
end;

Saludos :)

roman 14-10-2015 04:57:49

Hola ecfisa,

Esta última versión se ve mucho mejor pero me queda la duda de si no falla cuando la cadena termina en espacios. Por otro lado, no entiendo el uso de SetLength.

pd: buena observación de mamcx, ya que borrar un caracter implica el reacomodo del resto de la cadena.

// Saludos

ecfisa 14-10-2015 06:13:15

Hola roman.

Cometí un error de copia/pega de una de las varias pruebas,de ahí el SetLength :o. (Aunque acabo de hacerle unas comprobaciones e igual funciona con espacios sobre el final)

Debería haber sido esta:
Código Delphi [-]
function IgnoreExtraSpaces(const str: string): string;
var
  i: integer;
begin
  for i := 1 to Length(str) do
    if (str[i] <> ' ') or (str[i+1] <> ' ') then
      Result := Result + str[i];
end;

Saludos :)

Casimiro Notevi 14-10-2015 08:58:29

También se puede hacer una función recursiva, pero como se pide que sea lo más eficiente posible, habría que probar si la recursividad es más eficiente que el bucle :)

escafandra 14-10-2015 13:36:49

Otra opcion, esta vez en asm:
Código Delphi [-]
function BorraMultiespacios(S: String): String;
var
  Cadena: PCHAR;
begin
  Cadena:= @S[1];
  asm
  mov       edi, Cadena
  mov       esi, edi
@loop1:
  cmp       word ptr [esi], 2020h
  jne       @sigue
  inc       esi
  jmp       @loop1
@sigue:
  movsb
  cmp       byte ptr [esi], 0
  jne       @loop1
  mov       word ptr [edi], 0h
  end;
  Result:= Cadena;
end;

Saludos.

roman 14-10-2015 17:31:29

Cita:

Empezado por ecfisa (Mensaje 497901)
Hola roman.

Cometí un error de copia/pega de una de las varias pruebas,de ahí el SetLength :o. (Aunque acabo de hacerle unas comprobaciones e igual funciona con espacios sobre el final)

En esta versión, S[I+1] se sale de la cadena al final, lo cual puede ser inseguro. Supongo que por eso habías agrandado en 1 la longitud de la cadena en la versión anterior; aunque aún tendrías que asegurarte que en ese lugar extra no tienes un espacio que de casualidad ande por ahí. ¿Por qué no así?

Código Delphi [-]
function IgnoreExtraSpaces(str: string): string;
var
  i: integer;
begin
  // SetLength(str, Length(str)+1);
  str := str + #0;
  for i := 1 to Length(str)-1 do
    if (str[i] <> ' ') or (str[i+1] <> ' ') then
      Result := Result + str[i];
end;

// Saludos

roman 14-10-2015 17:57:51

Cita:

Empezado por escafandra (Mensaje 497916)
Otra opcion, esta vez en asm:
Código Delphi [-]
function BorraMultiespacios(S: String): String;
var
  Cadena: PCHAR;
begin
  Cadena:= @S[1];
  asm
  mov       edi, Cadena
  mov       esi, edi
@loop1:
  cmp       word ptr [esi], 2020h
  jne       @sigue
  inc       esi
  jmp       @loop1
@sigue:
  movsb
  cmp       byte ptr [esi], 0
  jne       @loop1
  mov       word ptr [edi], 0h
  end;
  Result:= Cadena;
end;

Saludos.

¡Joder! Sí que rizamos el rizo :D Seguro que así es lo más eficiente.

// Saludos

Casimiro Notevi 14-10-2015 18:07:41

Cita:

Empezado por roman (Mensaje 497938)
¡Joder! Sí que rizamos el rizo :D Seguro que así es lo más eficiente.
// Saludos

Habría que comprobarlo, lo mismo el compilador de delphi crea un código similar con alguna de las propuestas anteriores ;)
¿Alguien se anima a probar y calcular el tiempo con cada opción?

roman 14-10-2015 18:14:30

Cita:

Empezado por Casimiro Notevi (Mensaje 497940)
Habría que comprobarlo, lo mismo el compilador de delphi crea un código similar con alguna de las propuestas anteriores

Quién sabe. La misma RTL implementa algunas cosas en ensamblador. Sobre todo las que tienen que ver con el recorrido de cadenas.

Por otra parte, si usa una versión de Delphi que tenga expresiones regulares yo las usaría sin pestañear :) Por ejemplo, en php:

Código PHP:

function comprimeEspacios($s) {
  return 
preg_replace('/ +/'' '$s);


// Saludos

ecfisa 14-10-2015 18:28:10

Cita:

Empezado por roman (Mensaje 497931)
En esta versión, S[I+1] se sale de la cadena al final, lo cual puede ser inseguro. Supongo que por eso habías agrandado en 1 la longitud de la cadena en la versión anterior;...

Si exáctamente ese fué el motivo de aplicar esa precaución en las pruebas previas, pero luego recordé que no estaba tratando con un ShortString sino con un AnsiString por lo que no iba a tener problemas de desborde (excepto con un texto de largo 2^31). De todos modos agregar #0 es una buena medida.

De tanto escudriñar, también me encontré con una situación que no entiendo...
Haciendo,
Código Delphi [-]
var
  i : Integer;
  s : string;
begin
  s := 'prueba';
  Memo1.Lines.BeginUpdate;
  try
    for i := 1 to Length(s)+1000 do
      Memo1.Text := Memo1.Text + s[i];
  finally
    Memo1.Lines.EndUpdate;
  end;
end;
obtengo el resultado que me esperaba:


Sin embargo si hago,
Código Delphi [-]
var
  i : Integer;
  s, x: string;
begin
  s := 'prueba';
  x := '';
  for i := 1 to Length(s)+1000 do  x := x + s[i];
  Memo1.Text := x;
end;
obtengo este resultado:


:confused:

Saludos :)

roman 14-10-2015 18:34:54

Cita:

Empezado por ecfisa (Mensaje 497944)
luego recordé que no estaba tratando con un ShortString sino con un AnsiString por lo que no iba a tener problemas de desborde

No entiendo por qué dices esto. Un String no tiene una longitud predeterminada. Si accedes más allá de sus fronteras definidas en un momento dado, puedes tener problema accediendo a lugares que no corresponde.

// Saludos

roman 14-10-2015 18:43:47

Cita:

Empezado por ecfisa (Mensaje 497944)

Sin embargo si hago,
Código Delphi [-]
var
  i : Integer;
  s, x: string;
begin
  s := 'prueba';
  x := '';
  for i := 1 to Length(s)+1000 do  x := x + s[i];
  Memo1.Text := x;
end;
obtengo este resultado:

Posiblemente obtienes ese resultado porque la propiedad Text corta lo que esté después de un #0. Examina el valor de x justo antes de asignarlo a Memo1.Text y verás que ahí está lo de antes. Supongo que al aumentar caracter por caracter, se salta el cero pero sigu pniendo el resto.

// Saludos

roman 14-10-2015 18:44:51

Cita:

Empezado por ecfisa (Mensaje 497944)

Sin embargo si hago,
Código Delphi [-]
var
  i : Integer;
  s, x: string;
begin
  s := 'prueba';
  x := '';
  for i := 1 to Length(s)+1000 do  x := x + s[i];
  Memo1.Text := x;
end;
obtengo este resultado:

Posiblemente obtienes ese resultado porque la propiedad Text corta lo que esté después de un #0 al asignarla. Examina el valor de x justo antes de asignarlo a Memo1.Text y verás que ahí está lo de antes. Supongo que al aumentar caracter por caracter, se salta el cero pero sigue poniendo el resto.

// Saludos

ecfisa 14-10-2015 20:05:22

Cita:

Empezado por roman (Mensaje 497945)
No entiendo por qué dices esto. Un String no tiene una longitud predeterminada. Si accedes más allá de sus fronteras definidas en un momento dado, puedes tener problema accediendo a lugares que no corresponde.

// Saludos

Si, siempre lo entendí del mismo modo (de allí que empecé las pruebas extendiendo la cadena un espacio mas).
Pero contra toda predicción, no hubo advertencia ni errores al acceder a una posición mas allá del valor de Length, eso me dejó con dudas e hice múltiples pruebas sin lograr que se produzca advertencia o error alguno. De ahí que atribuí que obtenía ese resultado por tratar con un AnsiString.

Realmente siempre puse cuidado en no acceder a una posición mayor al largo de una cadena pensando en que generaría un error, pero todas las pruebas realizadas hasta ahora me indican que, al menos acceder (lectura) a una posición mas del valor devuelto por Length de un AnsiString no genera error.

¿ Conoces algún caso en que se produzca ?

Saludos :)


La franja horaria es GMT +2. Ahora son las 15:17:19.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi