Ir para conteúdo

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

demytrius

Pegando partes de texto

Recommended Posts

Tenho um arquivo 'cidades.txt' que contém o seguinte em cada linha:

5200050,'GO','Abadia de Goiás'

para cada cidade do brasil, um número, o UF e a cidade correspondente.

Gostaria de saber como eu faço para passar apenas o uf para um dbcombobox e selecionando aquele uf, ele mostre apenas as cidades correspondentes em um segundo combobox.

 

Alguém?

Desde já, obrigado.

Compartilhar este post


Link para o post
Compartilhar em outros sites

A primeira questão é: você tem alguma tabela na sua base de dados que tenha as cidades cadastradas com seus devidos estados? Se sim, a solução é simples: dois selects e você mata o problema. No primeiro, você vai carregar seu combo de estados usando apenas um select simples, como o abaixo:

 

Select distinct uf from tb_estados order by uf asc

Usando este select, você só precisa jogar os dados retornados por ele no seu primeiro combobox. Depois, no evento onexit deste combobox de estados, você mandaria rodar outro select para buscar as cidades daquele estado, algo como o select abaixo:

 

Select distinct cidade from tb_cidades where uf = 'RS' order by cidade asc

Ai é só montar sua rotina para carregar o segundo combobox. Agora, se for tentar fazer isso em cima de um txt, você vai se complicar... a sugestão que eu lhe dou é que importe este txt para uma tabela (atualizando sempre apenas os que mudarem ou não existirem na base de dados) e use tabelas dentro do seu bd para carregar os combobox. Para ler os registros do txt, depois que capturar a linha do txt você pode usar o comando copy. Tem vários exemplos aqui no fórum de como manipular arquivos txt e usar este comando.

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

A primeira questão é: você tem alguma tabela na sua base de dados que tenha as cidades cadastradas com seus devidos estados? Se sim, a solução é simples: dois selects e você mata o problema. No primeiro, você vai carregar seu combo de estados usando apenas um select simples, como o abaixo:

 

Select distinct uf from tb_estados order by uf asc

Usando este select, você só precisa jogar os dados retornados por ele no seu primeiro combobox. Depois, no evento onexit deste combobox de estados, você mandaria rodar outro select para buscar as cidades daquele estado, algo como o select abaixo:

 

Select distinct cidade from tb_cidades where uf = 'RS' order by cidade asc

Ai é só montar sua rotina para carregar o segundo combobox. Agora, se for tentar fazer isso em cima de um txt, você vai se complicar... a sugestão que eu lhe dou é que importe este txt para uma tabela (atualizando sempre apenas os que mudarem ou não existirem na base de dados) e use tabelas dentro do seu bd para carregar os combobox. Para ler os registros do txt, depois que capturar a linha do txt você pode usar o comando copy. Tem vários exemplos aqui no fórum de como manipular arquivos txt e usar este comando.

 

[]'s

Não, não tenho tabelas de UF's e Cidades, e não gostaria de ter que usar tabelas...

A minha fonte de dados é um arquivo txt em que cada linha tem o seguinte formato:

 

9999999,'UF','CIDADE'

 

Desde já, agradeço :)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmm, n tenho certeza, mas não seria o caso de usar length na linha?

 

Por exemplo, se o número que vem antes do UF tiver sei la, 10 caracteres..

 

1234567890,'UF','CIDADE'

 

contando com a virgula, seriam 11 caracteres.. n daria para colocar um copy em que tu fizesse o lenght da linha correspondente copiando da 12 até a 16? que seria o 'UF'?

 

Não conheço mto, mas acho que isso pode funcionar, se estiveres usando text file não? :S

 

[rs, desculpa se falei bobagem, mas ainda sou uma mera newbie rsrs]

 

boa sorte ;*

Compartilhar este post


Link para o post
Compartilhar em outros sites

Usar txt não será uma boa, por questão principalmente de performance amigo... imagine a situação: seu txt tem 200 mil linhas de registros, mas você só vai carregar 50 ... independente de você não querer gravar os dados no BD, você vai ser obrigado a criar no mínimo uma tabela temporária (uma Table talvez), onde você vai jogar os nomes das cidades e os estados. Porque isso? Simples... não tem como você garantir que no seu combobox os nomes de estados não serão repetidos lendo direto do txt, a menos que para cada registro lido você vá varrer todo o seu combobox para ver se o estado já foi ou não inserido nele... imagine o custo de processamento de fazer este teste 200 mil vezes no seu combox multiplicando isso por cada teste de laço de repetição que irá usar para isto... no melhor caso, você testaria 200 mil vezes para ver que o estado está no primeiro item do seu combobox. E depois você teria que calcular o custo para montar o combobox de cidades, visto que a cada mudança no combobox de estado você teria que limpar o combo de cidades, reler todos os 200 mil registros e comparar por testes se o estado que está lendo naquele momento é o estado selecionado e depois testar se a cidade que está lendo já foi ou não inclusa no combobox de cidades.

 

Eu recomendo ao amigo pensar um pouco nisto antes de implementar o código... se mesmo assim decidir usar o txt, a noite posso tentar ajudar melhor com o código (no serviço agora fica um pouco complicado, pois é um código que exige atenção para ser montado).

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmm, n tenho certeza, mas não seria o caso de usar length na linha?

 

Por exemplo, se o número que vem antes do UF tiver sei la, 10 caracteres..

 

1234567890,'UF','CIDADE'

 

contando com a virgula, seriam 11 caracteres.. n daria para colocar um copy em que tu fizesse o lenght da linha correspondente copiando da 12 até a 16? que seria o 'UF'?

 

Não conheço mto, mas acho que isso pode funcionar, se estiveres usando text file não? :S

 

[rs, desculpa se falei bobagem, mas ainda sou uma mera newbie rsrs]

 

boa sorte ;*

Juuh, acho que a tua idéia é muito válida =)

vou tentar botar na prática, eu não sei trabalhar muito bem com strings, se puderes me passar um exemplo de como fazer isso eu ficaria muito grato.

lembrando

são 7 numeros (9999999)

depois (,) e (')

totalizando 9 caracteres antes do "UF"

e para pegar apenas as cidades seriam 14 caracteres + 1 no fim da cidade(fim da linha -1).

espero que eu tenha sido suficientemente claro.

hehehe

Compartilhar este post


Link para o post
Compartilhar em outros sites

Chrnos, lendo tua argumentação sobre a perfomance do programa agora faz sentido.

Talvez seja melhor utilizar tabelas para UF e Cidades mesmo, e creio que seja possível encontrar tabelas prontas com os dados já cadastrados para UF e CIDADES.

será que é possível importar essas 2 tabelas para o meu arquivo.GDB?

 

Se sim, onde posso encontrá-las?

Como importá-las?

 

Abraço!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, eu tenho que concordar com o que o Chrnos disse... mas no caso que queira usar o txt, eu creio que ficaria assim:

 

ok, considere que o textfile eu vou chamar de arq e que tu tem uma variavel tipo string chamada linha, que corresponde a cada linha do txt

1234567,'UF','CIDADE'

 

9 caracteres antes, tem que copiar 2

 

copy (linha, length (linha) 10, 11)

 

acho que seria essa a estrutura não?

afinal a estrutura seria essa:

Copy(Str,Inicio,Quantidade)

 

certo? .-.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Criar tabelas é um comando sql básico... dependendo do BD que use, você pode montar a tabela com um assistente inclusive.

 

Vou considerar a tabela nesta estrutura para o código inicial que vou por aqui:

 

TB_CIDADES

CODIGO Autoincremento,

CIDADE varchar(100)

UF varchar(2)

 

Consideremos o exemplo que você está retornando do formato dos registros, que seja sempre fixo o número de caracteres até o nome da cidade, isto é, que o UF sempre venha informado na mesma posição:

 

1234567,'UF','CIDADE'

 

Assim sendo, temos:

 

As primeras 9 colunas não teremos uso neste exemplo;

O UF será lido sempre da coluna 10 a 11

A cidade será lida a partir da coluna 15 até lenght-1 da linha

 

procedure TForm1.ImportaRegistros;
var Arquivo  : TextFile;
	UF, Cidade,
	Registro : String;
	Sql : String;
begin
   try
	  {$I-}
		AssignFile(Arquivo, 'c:\arquivoteste.txt');
		Reset(Arquivo);
		while not Eof(Arquivo) do
		begin
		   Readln(Arquivo, Registro);
		   try
			   UF := copy(Registro,10,2);
			   Cidade := copy(Registro,15,length(Registro)-1);
			   //Showmessage apenas para você conferir se está pegando os dados corretamente... pode inibir depois
			   Showmessage('UF Lido: ' + UF + #13 + 'Cidade Lida: ' + Cidade);
			   //aqui você monta seu código para gravar na tabela
			   Sql := 'Insert into TB_CIDADES (CIDADE, UF) Values (' + QuotedStr(Cidade) + ',' + QuotedStr(UF) + ')' );
			   Query1.Close;
			   Query1.Sql.Clear;
			   Query1.Sql.Add(Sql);
			   Query1.ExecSql;
		   excepton E : Exception do
				//Em caso de erro, mostra a mensagem e qual o erro que ocorreu (Exception)
				Showmessage('Operação não pode ser realizada.' + #13 + E.Message);
		   end;
		end;
		CloseFile(Arquivo);
	  {$I+}
   except
   end;
end;

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Criar tabelas é um comando sql básico... dependendo do BD que use, você pode montar a tabela com um assistente inclusive.

 

Vou considerar a tabela nesta estrutura para o código inicial que vou por aqui:

 

TB_CIDADES

CODIGO Autoincremento,

CIDADE varchar(100)

UF varchar(2)

 

Consideremos o exemplo que você está retornando do formato dos registros, que seja sempre fixo o número de caracteres até o nome da cidade, isto é, que o UF sempre venha informado na mesma posição:

 

1234567,'UF','CIDADE'

 

Assim sendo, temos:

 

As primeras 9 colunas não teremos uso neste exemplo;

O UF será lido sempre da coluna 10 a 11

A cidade será lida a partir da coluna 15 até lenght-1 da linha

 

procedure TForm1.ImportaRegistros;
var Arquivo  : TextFile;
	UF, Cidade,
	Registro : String;
	Sql : String;
begin
   try
	  {$I-}
		AssignFile(Arquivo, 'c:\arquivoteste.txt');
		Reset(Arquivo);
		while not Eof(Arquivo) do
		begin
		   Readln(Arquivo, Registro);
		   try
			   UF := copy(Registro,10,2);
			   Cidade := copy(Registro,15,length(Registro)-1);
			   //Showmessage apenas para você conferir se está pegando os dados corretamente... pode inibir depois
			   Showmessage('UF Lido: ' + UF + #13 + 'Cidade Lida: ' + Cidade);
			   //aqui você monta seu código para gravar na tabela
			   Sql := 'Insert into TB_CIDADES (CIDADE, UF) Values (' + QuotedStr(Cidade) + ',' + QuotedStr(UF) + ')' );
			   Query1.Close;
			   Query1.Sql.Clear;
			   Query1.Sql.Add(Sql);
			   Query1.ExecSql;
		   excepton E : Exception do
				//Em caso de erro, mostra a mensagem e qual o erro que ocorreu (Exception)
				Showmessage('Operação não pode ser realizada.' + #13 + E.Message);
		   end;
		end;
		CloseFile(Arquivo);
	  {$I+}
   except
   end;
end;

[]'s

 

Chrnos, sim, eu sei criar tabelas via sql hehehehe :D

o que eu queria era saber se existem tabelas disponíveis na internet com os dados já preenchidos sobre UF e Cidades

com chaves linkando as cidades às suas respectivas UF's e como agregar essas tabelas ao meu bd já criado em formato gdb.

=)

ps: vou tentar incrementar este procedure seu no meu programa e se o desempenho não ficar prejudicado vou usá-lo

muito obrigado!

Compartilhar este post


Link para o post
Compartilhar em outros sites

demytrius, se o seu arquivo texto está completo, com cidades e estados, não há necessidade de ficar "caçando" na internet uma tabela com tais dados...

 

a rotina que o Chrnos passou já fará toda a importação dos dados, é só criar as tabelas...

 

obs: caso você encontre tais tabelas na net pra download, mesmo assim, muito provavelmente, você teria que fazer adaptações, e muito provavelmente até mesmo a importação de todos os dados com uma rotina parecida com essa do Chrnos ...

 

abraço !!!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ceerto, não tinha percebido que esse código era para importação dos dados do arquivo txt.

farei isso, caso ocorra algum erro, reportarei devolta aqui.

muito obrigado!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Chrnos, desculpe estar sendo incômodo, mas essa rotina precisa de algum objeto ou só implemento um botão na tela que faça isso?

e ela vai exportar em um banco separado do meu ou eu posso associar o meu para que as tabelas sejam criadas diretamente nele?

Compartilhar este post


Link para o post
Compartilhar em outros sites

demytrius, o exemplo que eu montei é bem genérico... a tabela você pode criar dentro do seu bd como faria para criar qualquer tabela e o código em sí que montei é uma procedure que você pode chamar em qualquer lugar do seu programa (um botão, um evento create, etc...). A única coisa que tem que declarar, se não me falha a memória agora, é a FileCtrl na lista de uses do form que contiver a procedure, e adaptá-la aos campos que irá ler e gravar na sua tabela.

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Chrnos

Certo, e as tabelas do banco de dados tem alguma especifidade?

 

devo criá-la como a seguir:

 

Create table CIDADES

(

cd_cidade integer not null,

nm_cidade varchar(50) not null,

cd_Uf integer not null,

nm_uf varchar(2) not null,

 

constraint pk_cidade primary key (cd_cidade))

 

Ou é melhor eu criar uma tabela para as cidades e uma para UFs?

no caso assim:

 

Create table CIDADES

(

cd_cidade integer not null,

nm_cidade varchar(50) not null,

constraint pk_cidade primary key (cd_cidade))

 

e

 

Create table UF

(

cd_uf integer not null,

nm_uf varchar(50) not null,

constraint pk_uf primary key (cd_uf))

 

Muito obrigado pela ajuda até então.

 

PS: pelo que percebi, se criar com chaves primárias, vai dificultar o funcionamento do teu código, vou criar de maneia mais simples, sem chaves apenas os campos cidade e uf e ver se funciona.

Abraço

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom.... se você for trabalhar com a primeira tabela, o campo código UF não é necessário, visto que você vai fazer pesquisas pelo campo nm_uf diretamente (algo como nm_uf = 'RS' ou nm_uf in ('RS','SP','RJ')). Se for usar duas tabelas, na sua tabela de cidades você vai ter que por o código da UF para linkar as duas tabelas, ou não vai ter como associar cidade e estado.

 

Se você só for utilizar o campo UF na tabela de cidades, talvez uma tabela só já seja o suficiente para isso... afinal, você provavelmente vai gravar na sua tabela de endereços o código da cidade e, por ele, tem como pesquisar por estado por exemplo quais são os clientes do seu sistema.

 

Agora, se na tabela de estados você for por mais informações além do código e da sigla (o nome por extenso do estado por exemplo), ai justifica ter uma tabela de cidades e uma de estados, para não duplicar informações desnecessariamente na base de dados.

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ocorreram os seguintes erros quando eu adaptei o código e tentei compilar:

 

"EXCEPT OR FINALLY EXPECTED (50)

EXCEPT OR FINALLY EXPECTED (59)

END EXPECTED BUT EXCEPT FOUND (62)"

 

segue o código readaptado:

procedure TForm1.Button1Click(Sender: TObject);
//gerar tabelas
var Arquivo  : TextFile;
	UF, Cidade,
	Registro : String;
	Sql : String;
begin
   try
	  {$I-}
		AssignFile(Arquivo, 'cidades.txt');
		Reset(Arquivo);
		while not Eof(Arquivo) do
		begin
		   Readln(Arquivo, Registro);
		   try
			   UF := copy(Registro,10,2);
			   Cidade := copy(Registro,15,length(Registro)-1);
			   //Showmessage apenas para você conferir se está pegando os dados corretamente... pode inibir depois
			   Showmessage('UF Lido: ' + UF + #13 + 'Cidade Lida: ' + Cidade);
			   //aqui você monta seu código para gravar na tabela
			   Sql := 'Insert into CIDADES (NM_CIDADE, NM_UF) Values (' + QuotedStr(Cidade) + ',' + QuotedStr(UF) + ')' );
			   IBQuery1.Close;
			   IBQuery1.Sql.Clear;
			   IBQuery1.Sql.Add(Sql);
			   IBQuery1.ExecSql;
		   excepton E : Exception do
				//Em caso de erro, mostra a mensagem e qual o erro que ocorreu (Exception)
				Showmessage('Operação não pode ser realizada.' + #13 + E.Message);
		   end;
		end;
		CloseFile(Arquivo);
	  {$I+}
   except
   end;

Compartilhar este post


Link para o post
Compartilhar em outros sites

Coloca o código completo da unit para ver se faltou algum end ou algo assim.

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

Vou te passar as informações mais importantes sobre este BD.

 

O cadastro de clientes conta com dois campos: UF e CIDADE, ambos são VARCHAR [2 e 30]

o meu interesse é que o usuário possa selecionar estes campos em Comboboxes, sendo que ao selecionar o RS porexemplo, no combobox da cidade seja filtrado para cidades daquele UF apenas.

 

Tenho um arquivo de dados .txt que contém estas informações, porém não estão em ordem de uf

vou postar este arquivo aqui para você visualizar.

 

O banco de dados é em formato *.gdb e eu utilizo componentes Interbase no meu programa para trabalhar com ele.

 

Qual você acha que é a melhor solução para o meu problema e como executá-la?

PS: é um problema que parece simples, mas como eu sou mero iniciante em programação se torna complicado.

 

Muito obrigado pela paciência.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Amigo, dê uma pesquisada no fórum e vai achar exemplos de como carregar seu combobox a partir de uma query (use a palavra combobox como filtro de pesquisa). Agora, quanto a sua rotina de importação, o código está quase correto acima, mas os erros relatados indicam que em algum trecho da sua unit está faltando algum end ou existe algum try mal codificado. Vamos aos erros:

 

EXCEPT OR FINALLY EXPECTED (50)

EXCEPT OR FINALLY EXPECTED (59)

 

As mensagem acima dizem que no seu código é esperado um comando Except ou Finally em duas linhas distintas... isso pode ocorrer por ter um TRY dentro do seu código que você esqueceu de por o Except <comandos> end ou o Finally <comandos> end, visto que o TRY é um bloco de comandos que segue esta regra:

 

TRY

<comandos>

EXCEPT (ou FINALLY)

<comandos>

End;

 

END EXPECTED BUT EXCEPT FOUND (62)

 

Este erro indica que em algum lugar você tem um begin que não foi finalizado. Por isso deve revisar o código da unit para verificar isto e por isto pedi que postasse o código da unit completo.

 

O resto é questão de você implementar consultas ao BD para carregar os combos conforme sua necessidade... no oncreate ou no onshow do form você carrega o combobox de estados (sugiro neste local porque só necessita carrega-lo uma vez) e no evento onchange do combobox de estados você dispara uma rotina que limpa o combo de cidades e o recarrega filtrando por estado e dando um order by pela descrição (nome) da cidade.

 

[]'s

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.