• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

Baderous

Parsing de string que representa lista

28 mensagens neste tópico

Tenho de fazer uma função que pegue numa string que representa uma lista e construa a lista, por exemplo:

"[12,23,34]" -> [12,23,34]

Até agora o que tenho é isto:

stringSInt :: String -> [int]
stringSInt l = stringSIntAC [] [] ' ' l
where stringSIntAC _ ac2 _ [] = ac2
      stringSIntAC ac1 ac2 c (x:xs) | not (isDigit x) = stringSIntAC ac1 ac2 x xs
			            | otherwise = if c == '[' then stringSIntAC (ac1 ++ [x]) ac2 c xs
							      else if c == ',' then stringSIntAC [x] (ac2 ++ [strint ac1]) c xs
									       else stringSIntAC ac1 ac2 c xs

O meu raciocínio baseia-se no seguinte: uso 3 variáveis numa função auxiliar (stringSIntAC).

- ac1: guarda os resultados parciais, isto, é, no exemplo de cima, vai guardando o 12, o 23 e depois o 34.

- ac2: acumulador para onde passo os resultados parciais de ac1 e onde a lista vai sendo construída.

- ac3: variável que guarda o caracter não dígito da string (para que possa detectar quando tenho de guardar os dígitos em ac1)

O problema encontra-se em:

else if c == ',' then stringSIntAC [x] (ac2 ++ [strint ac1]) c xs

onde invoco a função auxiliar com o ac1 com aquele valor. Ora isto funciona bem para o 1º elemento, mas para os seguintes já não. Alguém tem ideias?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A primeira coisa que acho que devias fazer, era remover os parêntesis.

Depois, acho que estás a complicar. Ainda não percebi muito bem o que queres fazer, mas vê o algoritmo que eu sugiro aqui: http://www.portugal-a-programar.pt/forums/topic/0-find-topic/?do=findComment&comment=197440

É mais ou menos o que estás a fazer, mas ligeiramente mais simples. É que ao estares a fazer testes com o c e com o x só estás a complicar...

EDIT:

Pegando na tua versão, e efectuando algumas modificações...

stringSInt :: String -> [int]
stringSInt l = stringSIntAC [] [] ' ' l
        where stringSIntAC ac1 ac2 _ [] = ac2 ++ [(read ac1)::Int]
              stringSIntAC ac1 ac2 c (x:xs) = if c == '[' then stringSIntAC ac1 ac2 x xs
                                                          else if c == ',' then stringSIntAC [] (ac2 ++ [(read ac1)::Int]) x xs
                                                                           else stringSIntAC (ac1++[c]) ac2 x xs

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Rui Carlos, consegui fazer através do raciocínio da outra thread:

stringSInt :: String -> [int]
stringSInt l = stringIntAC [] [] l
where stringIntAC _ ac2 [] = ac2
      stringIntAC ac1 ac2 (x:xs) | not $ isDigit x = if x == '[' then stringIntAC ac1 ac2 xs
						     else stringIntAC [] (ac2 ++ [strint ac1]) xs
				 | otherwise = stringIntAC (ac1 ++ [x]) ac2 xs

Assim fica resolvido sem usar a função read (que não era suposto usar neste caso).

Quanto aos parêntesis, não sei se estavas a falar do operador $ como usei agora.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não, estava a falar disto: stringSInt l = stringIntAC [] [] (tail.init$l)

Quanto ao read, foi para poder testar.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ah LOL! Estavas a falar dos parêntesis da string do input! Eu pensei que era do código. Mas é bem pensado.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Assim fica resolvido sem usar a função read (que não era suposto usar neste caso).

Pois.

stringSInt = read

Se não houvesse essa restrição ficava demasiado fácil ;)

Mas estás a complicar demasiado.

import Data.List
import Data.Char
import Control.Arrow

stringSInt :: String -> [int]
stringSInt ('[':s) = map read $ unfoldr fun s
  where fun [] = Nothing
        fun l = Just $ (second tail) $ (span isDigit l)

Onde está read seria a tua função strint

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas pessoal,

Tou aqui devolta de um trabalho para a universidade, em que tenho de fazer parsing a um ficheiro .CSV que trata de inscrições, mas não posso utilizar o parsec ou assim, não é que seja complicado, o problema é que um dos campos da inscrição é uma lista de strings, isto é, por exemplo:

nome, idade,sexo,razoes_inscricao
José,23,M," [ 'porque sim','porque nao' ] "
António,22,M," [ 'porque sim','porque nao' ] "

eu sei como base para fazer parsing do ficheiro, a função que estavam a discutir aqui, a que eu usei é assim:

organizar_Linhas :: String -> [string]
organizar_Linhas linha = organizar_LinhasAC [] [] linha
                                              where
                                                          organizar_LinhasAC [] ac2 [] = ac2
                                                          organizar_LinhasAC ac1 ac2 [] = ac2++[ac1]
                                                          organizar_LinhasAC ac1 ac2 (x:xs) | (x==',') = organizar_LinhasAC [] (ac2++[ac1]) xs
					                                                                           | otherwise = organizar_LinhasAC (ac1++[x]) ac2 xs

peço desculpa se se parece demasiadamento igual a aqui apresentada.

o problema é que quando faço o parsing e dando como exemplo o CSV acima, ele ficaria assim:

["José","23","M","\" [ 'porque sim' "," 'porque nao' ] \" "]
["António","22","M","\" [ 'porque sim' "," 'porque nao' ] \" "] 

ou seja, ele deveria dar toda a lista de razões como apenas um campo da inscrição, assim:

["José","23","M",[ "porque sim","porque nao" ] ]

já experimentei de várias maneiras mas ainda faziam pior...alguém me podia dar alguma luz sobre isto??  :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

ou seja, ele deveria dar toda a lista de razões como apenas um campo da inscrição, assim:

["José","23","M",[ "porque sim","porque nao" ] ]

Hmmm... Mas isso não é um tipo válido em Haskell.

Ou é uma lista de strings, ou então, uma lista de listas de strings.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

boas...

então se calhar a melhor maneira será  tentar obter a lista como uma string apenas, e depois se a precisar analisar posteriormente usar uma função que chame esse campo da CSV...

basicamente ficava com a inscrição assim:

["José","23","M","[porque sim,porque nao ]" ]

mesmo assim, tenho o problema da vígula que está la nesse campo que não sei bem como resolver. o que eu quero obter é o que esta acima, o que eu tenho é, como disse no outro post

["José","23","M","[porque sim","porque nao ]" ]

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

alguém pode dar uma dar uma dica ou opinião de como poderia fazer isto, talvez chamar novamente a funçao organizar_LinhasAC até encontrar ']', mas penso que iria dar asneira...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Esses dados estão mais estruturados como um tuplo que uma lista.. Algo como:

("José", 23, "M", ["porque sim", "porque não"])

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

isto é  a estrutura do CSV:

nome,email,curso,numero-de-aluno,universidade,curso-1,filiacao-empresa,jantar-da-conferencia,almocos-no-restaurante-panoramico,porque-se-inscreveu-nas-join,outro-1,dt

mas eu nao estava a conseguir trabalhar com (criei até umas funções para fazer o parsing mas dava-me sempre erro, apaguei-as e agora não tenho aqui para poder mostrar):

type Inscricao = (Nome, Email, N_aluno, Universidade, Curso, Curso_ext, Empresa, Jantar_op, Almocos_op, Razoes_insc, Outras_razoes_insc, Data_insc)
type Csv_inscricoes=[inscricao]

entao optei por converter cada uma das linhas do csv em uma lista, cada lista representava uma inscrição, mas surgiu-me o problema das vírgulas nas razões de inscrição, se alguém me poder dar uma luz sobre como poderei resolver isto...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Estou perdido, e não devo ser o único. Qual é o problema exactamente?

O que estás a fazer? Qual o resultado que estás a obter? E qual o resultado que era suposto obter?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tal como o IceBrain referiu, não faz sentido usar uma lista. Se não quiseres usar um tuplo, define um tipo usando o construtor data.

Relativamente às vírgulas na razão da inscrição, diria que isso é problema do formato de entrada. Se o conteúdo de um campo pode ter vírgulas, deveria ser usado outro separador. Tens que perguntar a quem definiu o problema como é que se deve lidar com as vírgulas.

Há várias alternativas, desde alterar o ficheiro de entrada, até considerar que só um campo é que pode conter vírgulas (e neste caso, fazes parsing de tudo o resto, e o que sobrar é o motivo).

Alguns exemplos de inputs davam jeito.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Vamos ver se consigo passar a ideia que realmente quero...

é asim, o meu programa recebe um ficheiro .csv e tenho de fazer o seu parsing, o formato é o seguinte:

nome, idade,sexo,razoes_inscricao
José,23,M,"['porque sim','porque nao' ] "
António,22,M,"[ 'porque sim','porque nao' ] "

Eu estou a fazer map com uma função que tirei ideia daqui para transformar cada linha do ficheiro numa lista, e o resultado final é uma lista de listas de strings:

organizar_Inscricao :: [string] -> [[string]]
organizar_Inscricao [] = []
organizar_Inscricao linha = map organizar_Linhas linha 

organizar_Linhas :: String -> [string]
organizar_Linhas linha = organizar_LinhasAC [] [] linha
                 where
                       organizar_LinhasAC [] ac2 [] = ac2
                       organizar_LinhasAC ac1 ac2 [] = ac2++[ac1]
                       organizar_LinhasAC ac1 ac2 (x:xs) | (x=='\'') = organizar_LinhasAC ac1 ac2 xs
                                                         | (x==',') = organizar_LinhasAC [] (ac2++[ac1]) xs
					         | otherwise = organizar_LinhasAC (ac1++[x]) ac2 xs

o problema, é que um dos campos, neste exemplo o "razoes_inscricao" é uma lista de strings e quando corro o programa ele dá algo do género:

[["José","23","M","\"[porque sim","porque nao]\""],["António","22","M","\"[porque sim","porque nao]\""]] 

mas eu quero que ele intrepete a lista [porque sim, porque nao] como "[porque sim,porque nao]" mas o programa esta a dividí-la por causa da vírgula e eu queria que isso não acontecesse, queria que o resultado final fosse:

[["José","23","M","[porque sim,porque nao]"],["António","22","M","[porque sim,porque nao]"]] 

Nota: o meu csv não tem apenas 4 campos, tem muitos mais, usei isto como exemplo, porque no meu caso também só tem um campo que é uma lista de strings

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tens que ler o último campo de forma diferente. Pode ir contando os valores que já leste, ou podes simplesmente " e simplesmente devolver o resto da string quando o encontrares.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Tens que ler o último campo de forma diferente. Pode ir contando os valores que já leste, ou podes simplesmente " e simplesmente devolver o resto da string quando o encontrares.

no meu caso, esse campo não é o último do csv, eu já pensei nisso de analisar até encontrar novamente " , mas não consegui implementar, não podes dar um exemplo básico sobre isso?

como em haskell não há ciclos...não consegui implementar isso

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Por isso é que eu disse para apresentares um exemplo de input, pois a solução para o problema depende do input.

Adiciona um argumento à função, que serve de flag a dizer se estás a ler esse campo ou não. Quando encontras as aspas, mudas a flag para dizer que estás dentro do campo, e quando voltares voltas a mudar para dizer que estás fora. E enquanto a flag estiver a True, fazes o mesmo que fazes no otherwise.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

não me tinha lembrado disso...acho que isso já vai servi, obrigado...depois faço um post aqui a dizer se funcionou!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Isso poderia ser lido decentemente usando uma máquina de estados (que é na prática o que essa flag fará). Assim, poder-se-iam ter estados diferentes para ler cada campo, de forma a reconhecer o tipo de dados certo.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

activei uma flag quando encontrava o " e depois desligava-a quando encontrava o " final, e já funcionou para o que eu queria. obrigado.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

não me tinha lembrado disso...acho que isso já vai servi, obrigado...depois faço um post aqui a dizer se funcionou!

olha uma coisa da para disponivilizares todo o teu codigo

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boas,embora eu tenha feito funcoes diferentes, eu tenho o mesmo problema que o punkzero, mas nao consigo fazer a flag, alguém me dá umas luzes sobre isso ?

o problema mesmo é que eu nao sei o que é uma flag, nem nunca fiz -.-

obrigado

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Uma flag neste caso é uma variável que te diz se uma propriedade se verifica ou não (mas concretamente, diz-te se estás a ler a razão ou não).

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Podes dar um pequeno exemplo, nao precisa de ter a ver com o meu problema , obrigado

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora