PDA

Ver la Versión Completa : Acerca de CommaText


JuanBCT
19-01-2005, 16:02:34
Hola, tengo una pequeña duda con la propiedad Commatext de los Stringlist... espero q me puedan ayudar. Estoy haciendo un procedimiento que toma los datos de una libreta de direcciones del Outlook (exportada a CSV). Primero cargo el archivo en un stringlist; y luego en otro separo por campos, con commatext. El problema que tengo es que los nombres que tienen un espacio en el medio, son separados por commatext igual q si hubiera una coma. Por ej, si yo tengo estas líneas:

Juan,juanbecette81@yahoo.com.ar
Juan José Becette,juanbecette81@yahoo.com.ar

En el primer caso, campos[0] contendría "Juan", y campos[1] contendría "juanbecette81@yahoo.com.ar"; q es precisamente lo que quiero. Pero en el segundo caso, me lo pasaría de la siguiente manera: campos[0]="Juan" y campos[1]="José". ¿Hay algo que esté haciendo mal? En algún mensaje del foro leí que los stringlist tienen una propiedad llamada Delimiter, donde uno especifica el caractér delimitador, pero no lo puedo encontrar (aunque en teoría Commatext separa donde encuentra una coma, no?). Quizás esa propiedad no la encuentre porque uso Delphi 3...

Bueno, voy a estar muy agradecido si alguien me puede ayudar. Les adjunto el código del procedimiento que hice, por si acaso:

procedure TImport_form.FlatSpeedButton1Click(Sender: TObject);
var
Archivocsv, Campos: Tstringlist;
I: Integer;
begin

//Creo las dos StringList: una contiene el archivo entero, otra los campos...
Archivocsv:=Tstringlist.create;
Campos:=Tstringlist.create;
try
//Cargo el archivo a la stringlist Archivocsv...
Archivocsv.LoadFromFile(Filelistbox1.FileName);
//Separo cada línea en campos con COMMATEXT y paso c/u al arreglo Campos
for I:=0 to Archivocsv.Count -1 do
begin
Campos.clear;
Campos.CommaText:=ArchivoCsv[I];

//Paso c/campo a la tabla
//Pone nro de cliente automáticamente...
if Datamodule1.Client.RecordCount=0 then ncli:=0
else ncli:=Datamodule1.Client['CLI_NUM'];
Datamodule1.Client.Last;
Datamodule1.Client.Insert;
Datamodule1.Client['CLI_NUM']:=ncli + 1;
//==============================================
Datamodule1.Client['CLI_NOM']:=Campos[0];
Datamodule1.Client['CLI_MAIL']:=Campos[1];
Datamodule1.Client.Post;
end;
finally
Archivocsv.Free;
Campos.Free;
end;
end;

Gracias, y saludos!

Héctor Randolph
19-01-2005, 20:51:20
Hola Juan!

Una posible solución es que generes o modifiques el archivo que contiene los correos de la siguiente manera:

"Juan","juanbecette81@yahoo.com.ar"
"Juan José Becette","juanbecette81@yahoo.com.ar"

Cuando asignas texto a la propiedad CommaText se trabaja con el formato SDF y la cadena es separada por comas o espacios, opcionalmente puedes asignar comillas dobles para separar por bloques como en el ejemplo anterior.

En algún mensaje del foro leí que los stringlist tienen una propiedad llamada Delimiter, donde uno especifica el caractér delimitador, pero no lo puedo encontrar (aunque en teoría Commatext separa donde encuentra una coma, no?).

Efectivamente, el componente TStringList maneja dos propiedades para separar texto, CommaText y DelimitedText; son similares excepto que CommaText asume que siempre separas por comas y en DelimitedText opcionalmente puedes definir la propiedad Delimiter para cambiar el caracter que será utilizado para separar en lugar de la coma y también puedes definir QuotedChar para cambiar el caracter que encierra bloques entre comillas.

Quizás esa propiedad no la encuentre porque uso Delphi 3...

Alguna vez utilicé Delphi 3, pero no recuerdo si TStringList tenía la propiedad DelimitedText. :confused:


Espero que te sea útil, un Saludo.

JuanBCT
19-01-2005, 21:20:50
Hola Héctor; gracias por tu respuesta!

Voy a probar hacer una rutina que recorra el archivo y que ponga las dobles comillas como me indicaste (ya que el Outlook los saca así, y sería muy engorroso ponerse a hacerlo manualmente)... aparte sigo sin encontrar la propiedad DelimitedText...

Saludos!

JuanBCT
21-01-2005, 16:22:42
Saben que acabo de probar en Delphi 5 a ver si me aparecía la propiedad DelimitedText y Delimiter de los stringlist... y siguen sin aparecer! No tendré que declarar algo en el uses, por ejemplo?
Gracias...

Lepe
22-01-2005, 14:20:50
En la ayuda de delphi viene


In TStringList

Capacity
CaseSensitive
Count
Duplicates
Objects
Sorted
Strings

Derived from TStrings

CommaText
DelimitedText
Delimiter
Names
QuoteChar
StringsAdapter
Text
Values


Además son propiedades de un Tstrings, por tanto lo tienen los combobox, listbox. etc.

Saludos

JuanBCT
26-01-2005, 20:28:55
Hola! Te muestro lo q aparece en mi Help

In TStringList

Capacity
Count
Duplicates
Objects
Sorted
Strings

Derived from TStrings

CommaText
Names
StringsAdapter
Text
Values
:(

Gracias por tu respuesta, de todas formas...

Lepe
27-01-2005, 11:49:17
Eso me pasa por listillo jejeje, bueno , pues vamos a lo que vamos:


function DelimitedText(lista:TStringList;Delimiter:char):string;
var i:integer;
begin
for i:= 0 to lista.count-2 do
result := result+ lista[i]+ Delimiter;
if lista.count > 1 then
result:= result+lista[lista.count-1]
end;


Vas a tener que crear otra rutina para añadir las comillas dobles, pero eso te lo dejo a ti.

Espero que te sirva

JuanBCT
27-01-2005, 15:35:41
Hola, Lepe; finalmente solucioné el tema haciendo dicha rutina... les muestro como me quedó el botón "Importar":

procedure TImport_form.FlatSpeedButton1Click(Sender: TObject);
var
Archivocsv, Campos: Tstringlist;
I: Integer;
S:string;
begin
Datamodule1.Client.Last;
//StringLists para el archivo y para los campos
Archivocsv:=Tstringlist.create;
Campos:=Tstringlist.create;
try
//Cargo el archivo a la stringlist Archivocsv...
Archivocsv.LoadFromFile(Filelistbox1.FileName);
//Rutina para agregar las doble comillas...
for I:=1 to Archivocsv.Count -1 do
begin
//Paso c/línea a un string para modificarla a mi gusto con insert
S:=Archivocsv.Strings[I];
//Modifico...
Insert('"', S, 1);
Insert('"', S, (Length(S))+1);
Insert('"',S,Pos(',',S));
Insert('"',S,Pos(',',S)+1);
Archivocsv.Strings[I]:=S;
end;
Archivocsv.SaveToFile(Filelistbox1.FileName);
//---------------------------------------------
Archivocsv.LoadFromFile(Filelistbox1.FileName);
//Separo en Campos con COMMATEXT
for I:=0 to Archivocsv.Count -1 do
begin
CoolGauge1.Progress:=I*100 div Archivocsv.Count;
Campos.clear;
Campos.CommaText:=ArchivoCsv[I];
//Paso c/campo a la tabla
//Pone nro de cliente automáticamente...
if Datamodule1.Client.RecordCount=0 then ncli:=0
else ncli:=Datamodule1.Client['CLI_NUM'];
Datamodule1.Client.Insert;
Datamodule1.Client['CLI_NUM']:=ncli + 1;
//==============================================
Datamodule1.Client['CLI_NOM']:=Campos[0];
Datamodule1.Client['CLI_MAIL']:=Campos[1];
Datamodule1.Client.Post;
end;
finally
Archivocsv.Free;
Campos.Free;
end;
end;

Me queda una inquietud... en el caso que yo quiera incluir la función que me pasaste en el mensaje anterior; como o en q parte lo hago?
Gracias por tu tiempo...

Lepe
27-01-2005, 16:42:51
En realidad mi funcion ahora no te hace falta, ya que recorres las lineas para poner las comillas dobles,así que aprovecha ese mismo ciclo para poner el separador coma.


Mi funcion simula el DelimitedText y Delimiter que existe en los TStringlist de delphi 6 o superior.

Despues de Releer todo el hilo, no creo que lo necesites; de todas formas te explico como va:

MIStringlist:

Pepe
Manuel
Jose Manuel
Antonio

y quieres que salga esto:

Pepe;Manuel;Jose Manuel;Antonio

Esto se consigue con una llamada del tipo:

var s:string;
s:= DelimitedText(MiStringList,';');


Saludos

JuanBCT
27-01-2005, 19:19:34
Estaba interesado en tu función porque ahora me pidieron pasar 3 campos más; me dí cuenta que no lo iba a poder seguir haciendo así porque yo buscaba la coma con la función POS de los string. El inconveniente era q esta devuelve la posición del 1er caracter q uno busca en la línea; ahora q tenía varias comas no iba a poder seguir insertandole comillas!
Pero bueno, lo acabo de solucionar copiando cada "campo" en strings temporales para así ponerles las comillas a c/u y luego concatenar todo; haciendo la línea. Gracias por todo! Les dejo el código final de la procedure q hice, por si a alguno le interesa...

procedure TImport_form.FlatSpeedButton1Click(Sender: TObject);
var
Archivocsv, Campos: Tstringlist;
I: Integer;
S,A,B,C,D,E,F,G,H,Y:string;
begin
Datamodule1.Client.Last;
//StringLists para el archivo y para los campos
Archivocsv:=Tstringlist.create;
Campos:=Tstringlist.create;
try
//Cargo el archivo a la stringlist Archivocsv...
Archivocsv.LoadFromFile(Filelistbox1.FileName);
//Rutina para agregar las doble comillas...
for I:=1 to Archivocsv.Count -1 do
begin
//Paso c/línea a un string para modificarla a mi gusto con insert
S:=Archivocsv.Strings[I];
//Modifico...
Insert('"', S, 1);
Insert('"', S, (Length(S))+1);
//Pone " antes y después de la 1er coma (ahora tengo q hacer q recorra
Insert('"',S,Pos(',',S));
Insert('"',S,Pos(',',S)+1);
//Voy separando cada campo, y les pongo comillas para luego
//concatenarlos...
E:=Copy(S,0,Pos(',',S));

A:=Copy(S,Pos(',',S)+1,((Length(S))-Pos(',',S)));
Insert('"',A,Pos(',',A));
Insert('"',A,Pos(',',A)+1);
F:=Copy(A,0,Pos(',',A));

B:=Copy(A,Pos(',',A)+1,((Length(A))-Pos(',',A)));
Insert('"',B,Pos(',',B));
Insert('"',B,Pos(',',B)+1);
G:=Copy(B,0,Pos(',',B));

C:=Copy(B,Pos(',',B)+1,((Length(B))-Pos(',',B)));
Insert('"',C,Pos(',',C));
Insert('"',C,Pos(',',C)+1);
H:=Copy(C,0,Pos(',',C));
//D queda como está....
D:=Copy(C,Pos(',',C)+1,((Length(C))-Pos(',',C)));
//Ahora, concateno todo en Y
Y:=concat(E,F,G,H,D);

Archivocsv.Strings[I]:=Y;
end;
Archivocsv.SaveToFile(Filelistbox1.FileName);
//---------------------------------------------
Archivocsv.LoadFromFile(Filelistbox1.FileName);
//Separo en Campos con COMMATEXT
for I:=0 to Archivocsv.Count -1 do
begin
CoolGauge1.Progress:=I*100 div Archivocsv.Count;
Campos.clear;
Campos.CommaText:=ArchivoCsv[I];
//Paso c/campo a la tabla
//Pone nro de cliente automáticamente...
if Datamodule1.Client.RecordCount=0 then ncli:=0
else ncli:=Datamodule1.Client['CLI_NUM'];
Datamodule1.Client.Insert;
Datamodule1.Client['CLI_NUM']:=ncli + 1;
//==============================================
Datamodule1.Client['CLI_NOM']:=Campos[0];
Datamodule1.Client['CLI_MAIL']:=Campos[1];
Datamodule1.Client['CLI_TEL']:=Campos[2];
Datamodule1.Client['CLI_CALIDAD']:=Campos[3];
Datamodule1.Client['CLI_TELLAB']:=Campos[4];
Datamodule1.Client.Post;
end;
finally
Archivocsv.Free;
Campos.Free;
end;
end;

Saludos!!!

Lepe
28-01-2005, 13:16:28
La libreria NKlibs, tiene rutinas para buscar la ocurrencia de un caracter varias veces, además de otras muchas rutinas casi necesarias en el tratamiento de nombres de archivos, busqueda de archivos, strings y algunas cosas más.

Buscala en google.


// Dada una subcadena y una cadena, hace una búsqueda ultrarápida de la
// subcadena dentro de la cadena, devuelve la posición de la subcadena
// dentro de la cadena, o 0 si no se encontró la subcadena.
// Es igual que Pos, salvo que en vez de una búsqueda secuencial, usa una
// variante de Boyer-Moore (Horspool).
function BMPos(const cPttrn, cTarget: String): Integer;
function BMFirst(const cPttrn, cTarget: String): Integer;
function BMNext(iPos: Integer): Integer;
function BMLast: Integer;

// Dada una cadena devuelve un TStringList con todas las ocurrencias
/// de la subsadena.
function BMAll(const cPttrn, cTarget: String): TStringList;


Saludos

Chogo
16-07-2013, 18:49:52
Desarrolle este procedimiento, le pasas un String y un TStringList, porque me encontré con el mismo problema de los espacios que se menciona al inicio.
La idea que el StringList nos lo devuelva con varios item.


procedure TForm2.ComasTexto(str: String; Lista: Tstringlist);
var
I: Integer;
cadena:String;
begin
Lista.Clear;
cadena:='';
for I := 1 to Length(str)+1 do
begin
if str[i] = ',' then
begin
lista.Add(cadena);
cadena:='';
end
else
begin
if str[i] =#0 then
lista.Add(cadena)
else
cadena:=cadena + str[i];
end;
end;
end;