Parser

9 respostas
tiagokos

Olá!
Preciso “desmontar” um arquivo texto, transformando-o em uma série de arrays.
A idéia é a seguinte, é um parser CYK (quem já fez uma cadeira chamada linguagens formais sabe do que estou falando), isso não interessa muito, porém o que preciso fazer é transformar este arquivo texto em 4 arrays, um para os terminais, um para as variaveis um para o valor inicial e um para as regras (o das regras precisa ser um array com dois parametros já que ele vai receber uma string e um valor a ser inserido no decorrer do meu programa).

Terminais [ Brazil ] [ Argentina ] [ England ] Variaveis [ S ] [ PES ] [ OBJ ] Inicial [ S ] Regras [ S ] > [ PES ] [ OBJ ] [ PES ] > [ SUJ ] [ VER ] [ PES ] > [ SUJ ] [ COMP ]

Só quero saber se alguém tem uma função que faça isto de exemplo para eu me basear, qualquer ajuda é bem vinda!

9 Respostas

davidbuzatto

Este arquivo é você quem decide o formato ou já é preestabelecido?
Se for você que decide o formato, você poderia utilizar XML ou JSON para formatar os dados, ai ficaria mais fácil para fazer o parser.

Em XML ficaria:
<gramatica>
    <terminais>
        <terminal valor="Brazil"/>
        <terminal valor="Argentina"/>
        <terminal valor="England"/>
    </terminais>
    <variaveis>
        <variavel valor="S"/>
        <variavel valor="PES"/>
        <variavel valor="OBJ"/>
    </variaveis>
    <inicial valor="S"/>
    <regras>
        <regra simboloInicio="S" levaA="PES OBJ"/>
        <regra simboloInicio="PES" levaA="SUJ VER"/>
        <regra simboloInicio="PES" levaA="SUJ COMP"/>
    </regras>
</gramatica>
Em JSON:
{
    "terminais": [
       "Brazil",
       "Argentina",
       "England"
    ],
    "variaveis": [
       "S",
       "PES",
       "OBJ"
    ],
    "inicial": "S",
    "regras": [
        { "simboloInicial": "S", "levaA": "PES OBJ" },
        { "simboloInicial": "PES", "levaA": "SUJ VER" },
        { "simboloInicial": "PES", "levaA": "SUJ COMP" },
    ]
}

Perceba que em JSON o texto fica mais "magro", pois não tem as tags de fechamento. O primeiro "abre chaves" especifica a gramática. Você pode estruturá-lo de outras formas também, colocando objetos dentro dos arrays "terminais" e "variáveis", da mesma forma que fiz com "regras", mas como os terminais e as variáveis só tem o valor, usei apenas um array. O que eu fiz é apenas uma sugestão. Mais informações sobre JSON vc pode encontrar no link http://www.json.org/.

Para fazer o parse do XML vc pode usar o SimpleXML (http://simple.sourceforge.net/) ou o XStream (http://xstream.codehaus.org/). Eu prefiro o SimpleXML
Para fazer o parse do JSON, existem diversas alternativas. Uma bem fácil de usar é o Jettison (http://jettison.codehaus.org/). O XStream também suporta JSON, mas também não gosto...

Entretanto, se o formato já for estabelecido, vc pode usar os métodos da classe String para ir recortando os valores, com base na formatação estabelecida.
Usando o split e o replace vc consegue fazer tudo.

Olha o exemplo (assumindo que existe quebra de linha (\n)):
String dados = "Terminais\n" +
        "[ Brazil ]\n" +
        "[ Argentina ]\n" +
        "[ England ]\n" +
        "Variaveis\n" +
        "[ S ]\n" +
        "[ PES ]\n" +
        "[ OBJ ]\n" +
        "Inicial\n" +
        "[ S ]\n" +
        "Regras\n" +
        "[ S ] > [ PES ] [ OBJ ]\n" +
        "[ PES ] > [ SUJ ] [ VER ]\n" +
        "[ PES ] > [ SUJ ] [ COMP ]";

// tira os colchetes
String gramatica = dados.replace( "[ ", "" ).replace( " ]", "" );

// gera um array de duas posições. na primeira, está toda a parte de "Terminais"
// na segundao restante da String (variaveis + inicial + regras).
String[] spTerm = gramatica.split( "Variaveis\n" );

// gera um array de duas posições (com base no final do spTerm).
// na primeira, está toda a parte de "Variaveis" na segundao restante da
// String (inicial + regras).
String[] spVar = spTerm[1].split( "Inicial\n" );

// gera um array de duas posições (com base no final do spVar).
// na primeira, está toda a parte de "Inicial" na segundao restante da
// String (regras).
String[] spIniReg = spVar[1].split( "Regras\n" );

// cria o array de terminais quebrando nos pulos de linha, sendo que 
// primeiro remove a String "Terminais\n" que ficou sobrando no processo 
// anterior.
String[] terminais = spTerm[0].replace( "Terminais\n", "" ).split( "\n" );

// cria o array de variáveis (quebra nos pulos de linha)
String[] variaveis = spVar[0].split( "\n" );

// inicial vai ser sempre um só (definição na teoria), mas ainda
// precisa remover o pulo de linha
String inicial = spIniReg[0].replace( "\n", "" );

// cria o array de regras (quebra nos pulos de linha)
String[] regras = spIniReg[1].split( "\n" );


// mostra cada um
System.out.println( "terminais:" );
for ( String terminal : terminais ) {
    System.out.println( terminal );
}

System.out.println();

System.out.println( "variáveis:" );
for ( String variavel : variaveis ) {
    System.out.println( variavel );
}

System.out.println();

System.out.println( "inicial: " + inicial );

System.out.println();

System.out.println( "regras:" );
for ( String regra : regras ) {

    // quebrando a regra atual...
    String[] sRegra = regra.split( " > " );

    // em 0 está o símbolo inicial de regra, no 1 está o corpo da regra
    String simboloInicio = sRegra[0];
    String levaA = sRegra[1];

    System.out.println( "símbolo inicio: " + simboloInicio + ", leva a: " + levaA );

}

Nossa, hehe, acabei fazendo tudo ;)

Ah, uma coisa que você precisa tomar cuidado é que se houver algum terminal, ou variável que tenha como nome os valores que estão sendo usados para o recorte (Variáveis, Inicial e Regras), o código acima vai ter problemas, pois vai fazer mais recortes que o "esperado". Então sugiro que você use uma das duas soluções apresentadas acima (XML ou JSON). Eu prefiro JSON, mas XML pode ser mais fácil de ler para algumas pessoas.

[]´s

davidbuzatto

Ainda mais simples:

String dados = "Terminais\n"
        + "[ Brazil ]\n"
        + "[ Argentina ]\n"
        + "[ England ]\n"
        + "Variaveis\n"
        + "[ S ]\n"
        + "[ PES ]\n"
        + "[ OBJ ]\n"
        + "Inicial\n"
        + "[ S ]\n"
        + "Regras\n"
        + "[ S ] > [ PES ] [ OBJ ]\n"
        + "[ PES ] > [ SUJ ] [ VER ]\n"
        + "[ PES ] > [ SUJ ] [ COMP ]";

// tira os colchetes
dados = dados.replace( "[ ", "" ).replace( " ]", "" );

// usando uma expressão regular, quebrando em Terminais\n ou Variáveis\n...
String[] gramatica = dados.split( "Terminais\n|Variaveis\n|Inicial\n|Regras\n" );

String[] terminais = gramatica[1].split( "\n" );
String[] variaveis = gramatica[2].split( "\n" );
String inicial = gramatica[3].replace( "\n", "" );
String[] regras = gramatica[4].split( "\n" );

// mostrando...
System.out.println( "terminais:" );
for ( String terminal : terminais ) {
    System.out.println( terminal );
}

System.out.println();

System.out.println( "variáveis:" );
for ( String variavel : variaveis ) {
    System.out.println( variavel );
}

System.out.println();

System.out.println( "inicial: " + inicial );

System.out.println();

System.out.println( "regras:" );
for ( String regra : regras ) {

    // quebrando a regra atual...
    String[] sRegra = regra.split( " > " );

    // em 0 está o símbolo inicial de regra, no 1 está o corpo da regra
    String simboloInicio = sRegra[0];
    String levaA = sRegra[1];

    System.out.println( "símbolo inicio: " + simboloInicio + ", leva a: " + levaA );

}
tiagokos

Opa, muito obrigado pela ajuda!
Vou dar uma olhada no código que tu fez hoje a noite.
Só uma coisa, como eu vou fazer para transformar o meu arquivo txt (o arquivo seria o code do meu primeiro post) em uma string de dados como ta montada no teu exemplo?

Obrigado (denovo hehe)!

davidbuzatto

Olá,

Então, para ler os dados do arquivo você tem diversas opções, sendo que uma das mais simples é usar um Scanner.

StringBuilder dadosArquivo = new StringBuilder();
Scanner scan = new Scanner( new File( "caminho do seu arquivo .txt" ) );

while ( scan.hasNextLine() ) {
    dadosArquivo.append( scan.nextLine() + "\n" );
}

String dados = dadosArquivo.toString();

// aqui vem o código que passei...

[]´s

tiagokos

Estou migrando do C para o JAVA e fico maravilhado como essa parte de manipulação de arquivos é extremamente simples.

Obrigado mais uma vez! Já tenho bastante coisa para fazer esta noite, malditos trabalhos relâmpagos da facul :smiley:

tiagokos

Bom alguém já ouviu falar em CYK? Possui algum parser parecido? A lógica é simples porém o trabalho é duro e o tempo é curto, qualquer ajuda é bem-vinda!

Primeiramente to precisando transformar as REGRAS em uma ARRAY de ARRAYS, cada índice de REGRAS deverá conter 4 índices, 0 = Primeira Parte, 1 = Segunda Parte, 3 = Terceira Parte (se houver, se não houver deixa vazio ou nulo), 4 = Valor.

[ SUJ ] > [ Germany ] ;1

Deverá ficar:
REGRAS[0][0] -> SUJ
REGRAS[0][1] -> Germany
REGRAS[0][2] -> null ou zero
REGRAS[0][3] -> 1 (pode ser em String)


Já consegui!

ViniGodoy

tiagokos:
Estou migrando do C para o JAVA e fico maravilhado como essa parte de manipulação de arquivos é extremamente simples.

Obrigado mais uma vez! Já tenho bastante coisa para fazer esta noite, malditos trabalhos relâmpagos da facul :D

Bom, no C eu não sei, mas no C++ manipular arquivos assim é tão simples quanto. Se não for até mais simples:
http://www.boost.org/doc/libs/1_43_0/libs/regex/doc/html/index.html


http://rapidxml.sourceforge.net/manual.html

tiagokos

Consegui acabar o trabalho, só está faltando uma parte.
Preciso construir uma árvore de derivação.

Alguém tem uma idéia de algoritmo que eu possa construir uma árvore de derivação para uma matriz quadrada?

Exemplo, matriz 5x5:

S null null null null
null null null null null
PES null null null null
PES null null OBJ null
SUJ VER VER NOM QUANT

Preciso constuir algo do tipo:

tiagokos

De uma forma mais simples, como imprimir uma árvore encadeada desta maneira:

Criado 31 de maio de 2010
Ultima resposta 4 de jun. de 2010
Respostas 9
Participantes 3