/ Forside / Teknologi / Udvikling / C/C++ / Nyhedsindlæg
Login
Glemt dit kodeord?
Brugernavn

Kodeord


Reklame
Top 10 brugere
C/C++
#NavnPoint
BertelBra.. 2425
pmbruun 695
Master_of.. 501
Bech_bb 500
kyllekylle 500
jdjespers.. 500
gibson 300
scootergr.. 300
molokyle 287
10  strarup 270
Logisk fejl/problem i C++
Fra : Preben Holm


Dato : 22-09-05 21:30

Hej gruppe,

jeg har et meget mystisk problem.

Det er meningen at jeg skal parse en fil som indeholder properties og
attributes - som sådan virker min løsning ganske udmærket, men med
visse uheldige sammensætninger, som bevirker, at det ikke altid virker
som det skal.

Et eksempel er følgende:
--------------------------------------------
{ "Link0"
Position (0, 0, 0)
RPY (0, 0, 0)
ReferenceFrame ""
Attributes
Link
}

{ "Link1"
Position (0, 0, 0.0)
RPY (0, 0, 0)
ReferenceFrame "Link0"
Attributes
Link
JointName "axis0"
ActiveJoint
Revolute
JointPosLimit -185 185
JointVelLimit 156
JointAccLimit 312
}
--------------------------------------------

For hver "{" til "}" er der tale om et nyt "objekt".
Jeg læser en linie ad gangen, og får udtrykt en property (f.eks.
Position) ved navn på property og så også parameteren.

Dette gemmes i klasser af typen Property. Dernæst er der tale om
attributter.

Når jeg når attributterne, så læses f.eks. "Link" korrekt, men JointName
forkert, fordi der tilføjes et mellemrum. Om det er fordi der tidligere
er læst en attribut uden værdi og der så kommer en værdi, eller det er
fordi, det er en attribut har jeg meget svært ved at finde ud af. Men
Det er her problemet er.
Jeg synes det er lidt fake, bare at "trimme" navnet efterfølgende, fordi
der er et mellemrum-tegn for meget. - Jeg vil hellere finde årsagen til
mellemrummet.

Funktionen addProperty i klassen Device sørger for at videregive en
linie (fra filen) med en property til klassen Device's constructor.
Ligeledes virker addAttribute. Attribute klassen nedarver fra Property.

Jeg indsætter det essentielle kode herunder:

Fra Attribute.h
--------------------
#ifndef _ATTRIBUTE_H_
#define _ATTRIBUTE_H_

#include "Property.h"

namespace Graphics {

class Attribute : public Property {
public:
// Constructers
Attribute();
Attribute(const std::string& parseString) : Property(parseString) {}
Attribute(const std::string& name, const std::string& value) :
Property(name, value) {}
virtual ~Attribute();

protected:

private:
};
}

#endif //_ATTRIBUTE_H_
--------------------


Fra Property.cpp
--------------------
Property::Property(const std::string& parseString) {
_name = "";
_value = "";
std::string s = parseString;

int i = 0, val = 0;
while ((int) s.find("\t", i) == i || (int) s.find(" ", i) == i) {i++;}
val = s.find(" ", i);

if (val >= 0)
_name = s.substr(i, val-1) + ".";
else
_name = s.substr(i, (int) s.size() - i - 1) + ".";

int vallen = (int) s.size() - val - 2;
if (val != -1)
_value = s.substr(val+1, vallen); // The "\n" omitted
else
_value = "";

std::cout << "Name: " << _name << std::endl;
std::cout << "Value: " << _value << std::endl << std::endl;
}
--------------------



Fra DeviceParser.cpp
--------------------
void DeviceParser::loadObjects(std::ifstream& ifs) {
std::string param;

while(getline(ifs, param)) {
if ((int) param.find("{") >= 0) {
// Begin read object
Device device;
std::string s;

bool attrib = false;

while(getline(ifs, s)) {
if ((int) s.find("}") >= 0)
break;

if ((int) s.find("Attributes") >= 0)
attrib = true;
else {
if (attrib != true) {
// Property found
device.addProperty(s);
} else {
// Attribute found
device.addAttribute(s);
}
}
}
_devices.push_back(device);
}
}
}
--------------------


Resten af koden ses på www.interrupt.dk/deviceparser.tar.gz




På forhånd mange tak for hjælpen!


Med venlig hilsen
Preben Holm

 
 
Michael Rasmussen (22-09-2005)
Kommentar
Fra : Michael Rasmussen


Dato : 22-09-05 19:49

On Thu, 22 Sep 2005 22:30:18 +0200, Preben Holm wrote:

>
> Det er meningen at jeg skal parse en fil som indeholder properties og
> attributes - som sådan virker min løsning ganske udmærket, men med
> visse uheldige sammensætninger, som bevirker, at det ikke altid virker
> som det skal.
>
I situationer som den du er havnet i, er det nogen gange en god ide, hvis
man sætter sig ned og laver en tilgangsgraf. En tilgangsgraf har til
formål, at vidr hvorledes input flyder gennem systemet, og hvordan
systemet skifter tilstand som konsekvens af input, og bruges ofte i
forbindelse med design af lex og parser

--
Hilsen/Regards
Michael Rasmussen
http://keyserver.veridis.com:11371/pks/lookup?op=get&search=0xE3E80917


Mogens Hansen (22-09-2005)
Kommentar
Fra : Mogens Hansen


Dato : 22-09-05 21:46


"Preben Holm" <64bitNOSPAMNO@mailme.dk> wrote in message
news:4332f801$0$49013$14726298@news.sunsite.dk...
> Hej gruppe,
>
> jeg har et meget mystisk problem.
>
> Det er meningen at jeg skal parse en fil som indeholder properties og
> attributes - som sådan virker min løsning ganske udmærket, men med visse
> uheldige sammensætninger, som bevirker, at det ikke altid virker som det
> skal.

Parsning af tekst er svært - hvis det skal virke robust.
F.eks. får du læst devices selvom der ikke er nogen } i teksten
Som Michael Rasmussen skriver kan det være en ide at lave en
tilstandsmaskine for parseren.

Personligt skal jeg ikke parse ret meget tekst, før jeg benytter
Boost::Spirit (http://www.boost.org/libs/spirit/index.html).
Det virker måske lidt mere kompliceret til at starte med, men det er langt
simplere at lave rigtigt og vedligeholde. Man bruger en formel syntaks
specifikation, der ligger tæt på EBNF.


>
> Et eksempel er følgende:
> --------------------------------------------
> { "Link0"
> Position (0, 0, 0)
> RPY (0, 0, 0)
> ReferenceFrame ""
> Attributes
> Link
> }
>
> { "Link1"
> Position (0, 0, 0.0)
> RPY (0, 0, 0)
> ReferenceFrame "Link0"
> Attributes
> Link
> JointName "axis0"
> ActiveJoint
> Revolute
> JointPosLimit -185 185
> JointVelLimit 156
> JointAccLimit 312
> }
> --------------------------------------------
>
> For hver "{" til "}" er der tale om et nyt "objekt".
> Jeg læser en linie ad gangen, og får udtrykt en property (f.eks. Position)
> ved navn på property og så også parameteren.
>
> Dette gemmes i klasser af typen Property. Dernæst er der tale om
> attributter.
>
> Når jeg når attributterne, så læses f.eks. "Link" korrekt, men JointName
> forkert, fordi der tilføjes et mellemrum. Om det er fordi der tidligere er
> læst en attribut uden værdi og der så kommer en værdi, eller det er fordi,
> det er en attribut har jeg meget svært ved at finde ud af. Men Det er her
> problemet er.

Koden kan simplificeres en del, og så ser det ud til at virke.
Se nedenfor.


[8<8<8<]
> Property::Property(const std::string& parseString) {
> _name = "";
> _value = "";

Hvis _name og _value er string objekter er den tildeling overflødig.
Foretræk iøvrigt initialisering frem for tildeling

Property::Property(const std::string& parseString) :
_name(""),
_value("")
{

selvom det også er overflødigt.

> std::string s = parseString;

Den kopi er overflødig.

>
> int i = 0, val = 0;

Typen som string::find returnerer er string::size_type - ikke int.
Derfor
string::size_type i = 0, val = 0;
så slipper du for alle de cast

> while ((int) s.find("\t", i) == i || (int) s.find(" ", i) == i) {i++;}

Du kan måske bruge funktionen isspace

> val = s.find(" ", i);
>
> if (val >= 0)
> _name = s.substr(i, val-1) + ".";

Det skal vist være s.substr(i, val-i)

> else
> _name = s.substr(i, (int) s.size() - i - 1) + ".";

Ved at droppe anden parameter får du resten af teksten: s.subst(i);

>
> int vallen = (int) s.size() - val - 2;
> if (val != -1)
> _value = s.substr(val+1, vallen); // The "\n" omitted
> else
> _value = "";

Den else er overfløde.
Ved at undlade den syntes jeg at koden tydeligere viser at value er
optionel.

[8<8<8<]
> void DeviceParser::loadObjects(std::ifstream& ifs) {

Det er egentligt tilstrækkeligt at bruge en istream& i stedet for en
ifstream&.


[8<8<8<]
> Resten af koden ses på www.interrupt.dk/deviceparser.tar.gz

Den kan jeg ikke umiddelbart få downloaded.

Prøv (jeg syntes det er mere overskueligt og det ser ud til at virke inden
for de begrænsninger din kode har):
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

const char* FILE_CONTENT =
"{ \"Link0\"\n"
" Position (0, 0, 0)\n"
" RPY (0, 0, 0)\n"
" ReferenceFrame \"\"\n"
" Attributes\n"
" Link\n"
"}\n"
"\n"
"{ \"Link1\"\n"
" Position (0, 0, 0.0)\n"
" RPY (0, 0, 0)\n"
" ReferenceFrame \"Link0\"\n"
" Attributes\n"
" Link\n"
" JointName \"axis0\"\n"
" ActiveJoint\n"
" Revolute\n"
" JointPosLimit -185 185\n"
" JointVelLimit 156\n"
" JointAccLimit 312\n"
"}\n";


void parse_property(const std::string& s)
{
string _name = "";
string _value = "";

string::size_type i = 0;
while (s.find('\t', i) == i || s.find(' ', i) == i) {i++;}
string::size_type val = s.find(' ', i);


if (val != string::npos) {
_name = s.substr(i, val-i);
_value = s.substr(val+1); // The rest of the line
}
else {
_name = s.substr(i); // The rest of the line
}

std::cout << "Name: ." << _name << "." << std::endl;
std::cout << "Value: ." << _value << "." << std::endl << std::endl;
}

void parse_device(std::istream& ifs)
{
string line;

while(getline(ifs, line)) {
if (line.find("{") != string::npos) {
// Begin read object
bool attrib = false;

while(getline(ifs, line)) {
if (line.find("}") != string::npos)
break;

if (line.find("Attributes") != string::npos) {
attrib = true;
continue;
}

if (attrib != true) {
// Property found
cout << "Property: ";
parse_property(line);
}
else {
// Attribute found
cout << "Attribute: ";
parse_property(line);
}
}
}
}
}

int main()
{
stringstream is(FILE_CONTENT);
parse_device(is);
}

Venlig hilsen

Mogens Hansen



Søg
Reklame
Statistik
Spørgsmål : 177428
Tips : 31962
Nyheder : 719565
Indlæg : 6407943
Brugere : 218877

Månedens bedste
Årets bedste
Sidste års bedste