Toon posts:

[Delphi] woorden uit tekst bestand halen

Pagina: 1
Acties:
  • 340 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Mijn probleem is als volgt:

Ik heb een tekst bestand waar ik een woord uit de eerste regel nodig heb.
De indeling van het de eerste regel is als volgt:

<woord1> woord(en)2 </woord1>
(lijkt beetje op html maar is het niet)

Ik heb de woorden die op plaats 2 staan nodig in bijvoorbeeld een label.caption.

Ik denk dat het makkelijkst is om de te zoeken naar het teken '>'en dan alles te pakken tot en met '<'.
Maar hoe krijg dat een beetje simpel voor elkaar?

Ik ben een redelijke newbie, maar moet een programmatje schrijven om tienduizenden bestanden te converteren, anders moet ik het handmatig doen |:(

  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

lijkt op XML ;)
en er is voor Delphi denk ik ook wel een XML parser beschikbaar.

Zelf een parser schrijven kan natuurlijk ook ;)

Verwijderd

Topicstarter
Op dinsdag 05 maart 2002 12:11 schreef wasigh het volgende:
lijkt op XML ;)
en er is voor Delphi denk ik ook wel een XML parser beschikbaar.

Zelf een parser schrijven kan natuurlijk ook ;)
XML? zegt me niet zoveel
De tekst is afkomstig van een soort database waar heel veel images aanhangen welke gerenamed moeten worden.
De images krijgen de benaming uit de eerste regel van het tekst bestandje. Denk dat je de eerste regel in een aray moet laden ofzo... iemand een idee?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 30-08 09:55

Creepy

Tactical Espionage Splatterer

Zoals gezegd lijkt het op een XML bestand, dus gebruik de standaard XML componenten die bij Delphi 6 zitten.. geen Delphi 6 maar een oudere? ff XML componenten zoeken op bijv. www.torry.net

Hoe werken de XML componenten? Zoek maar op in de Delphi help.

ALs je er 100% zeker van bent dat het geen XML bestand is, dan kan/moet je zelf gaan parsen. Files lezen in Delphi kan op meerdere manieren (m.b.v. assignfile/readln of m.b.v. een stringlist), dus zoek eens een leuke Delphi tutorial op, daarin wordt dat vast wel behandeld.

Als je dus zelf die dingen in gaat lezen, zul je ook wat bewerkening op strings moeten doen.. hiervoor geldt ook: Ga de Delphi help in. En zoek dan op string handling routines.

Maar als die bestanden de output zijn van een database, is het zeer waarschijnlijl WEL xml.

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Om zelf een parser te schrijven kun je het volgende doen:
- FileStream openen (TFileStream)
- Alles inlezen in één buffer (bijv. PChar)
- Een TStringList creëren.
- TStringList.Text = StringReplace(Buffer, ' ', #13#10, [rfReplaceAll)

Nu heeft je StringList alle items keurig gescheiden (je kant met behulp van Items[index] keurig door alle items lopen).

Rest zelf even proberen! Is i.i.g. niet zo moeilijk.

Verwijderd

Topicstarter
Ok bedankt

Het is geen XML, heb het even nagezocht. De bestanden zijn ook niet afkomstig van een database, het lijkt er alleen erg op.
Ik zal eens kijken of ik er uit kom...bedankt iig

Verwijderd

<woord1> woord(en)2 </woord1>

Ik heb de woorden die op plaats 2 staan nodig in bijvoorbeeld een label.caption.

Ik denk dat het makkelijkst is om de te zoeken naar het teken '>'en dan alles te pakken tot en met '<'.
Maar hoe krijg dat een beetje simpel voor elkaar?
Waarom niet gewoon een Combinatie van Copy en Pos?

Als je je regel hebt ingelezen met een simpel ReadLn en het hebt opgeslagen in een Woorden:string, kun je als volgt doen.
code:
1
2
3
4
5
6
7
8
i:=Pos('>', Woorden);
// geeft je de positie van je eerste '>', ofel het einde van <Woord1>
Woorden:=Copy(Woorden, i+1, Length(Woorden));
//maakt Woorden tot ' Woord2 </Woord1>' 
i:=Pos('<', Woorden);
//geeft de posities van het begin van '</Woord1>'
Woorden:=Copy(Woorden, 1, i-1);
//Woorden is nu ' Woord2 '; door i.p.v. i+1 en i-1 gebruik te maken van i+2 en i-2 krijg je 'Woord2'

Je kunt dit ook wel tot een lange brij samenvoegen, maar dan snapt geen hond meer wat je doet :). Een kortere manier van schrijven die toch leesbaar is:
code:
1
2
Woorden:=Copy(Woorden, Pos('>', Woorden)+1, Length(Woorden));
Woorden:=Copy(Woorden, 1, Pos('<', Woorden)-1);

Verwijderd

PS. Wat inlezen betreft, hoef je ook niet zonodig met Filestreams te spelen (ik ben er zelf doodsbang voor :)).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure AllesInEen;
var 
  MyTextFile: textfile;
  Woorden: string;
begin
  AssignFile(MyTextFile, 'SomeFileNameAndPath');
  Reset(MyTextFile);
  Readln(MyTextFile, Woorden);  
  CloseFile(MyTextFile);
  Woorden:=Copy(Woorden, Pos('>', Woorden)+1, Length(Woorden));
  Woorden:=Copy(Woorden, 1, Pos('<', Woorden)-1);
  MyLabel.Caption:=Woorden;
end;

Succes ermee.

Verwijderd

Op dinsdag 05 maart 2002 19:17 schreef Ublis het volgende:
PS. Wat inlezen betreft, hoef je ook niet zonodig met Filestreams te spelen (ik ben er zelf doodsbang voor :)).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure AllesInEen;
var 
  MyTextFile: textfile;
  Woorden: string;
begin
  AssignFile(MyTextFile, 'SomeFileNameAndPath');
  Reset(MyTextFile);
  Readln(MyTextFile, Woorden);  
  CloseFile(MyTextFile);
  Woorden:=Copy(Woorden, Pos('>', Woorden)+1, Length(Woorden));
  Woorden:=Copy(Woorden, 1, Pos('<', Woorden)-1);
  MyLabel.Caption:=Woorden;
end;

Succes ermee.
Waarom doodsbang voor FileStreams? Delphi gebruikt ze zelf ook. Bovendien is bovengenoemde manier de 'ouderwetse' manier.

Hieronder een voorbeeld van een eigengeschreven parser, werkt op HTML/XML/whatever. Onderstaande manieren worden ondersteund:
code:
1
2
3
4
5
6
7
8
<Dit is een test>Drie woorden hier
  <Inherited test>Vijf woorden zijn hier geplaatst
  </iNHERITED TeSt>
  </Een enkel item>Twee woorden
</DiT iS eEn test>
</Woorden>bla bla bla bla
bladerdebla
<Meer woorden>Jediejediejedieje</Meer WOORDEN>

Voor het voorbeeld laat ik alles in een TreeView plaatsen zodat de hiërarchie snel duidelijk wordt.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
function GetString(const FileName: String): String;
var
  FS: TFileStream;
begin
  Result:='';
  try
    FS:=TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
    with TStringStream.Create('') do
    try
      CopyFrom(FS, FS.Size);
      Result:=Trim(Result+DataString);
    finally
      Free;
    end;
    finally
    FS.Free;
    end;
  except
    raise;
  end;
end;

function ParseString(sString: String): TStringList;
var
  I, J: Integer;
begin
  Result:=TStringList.Create;
  sString:=StringReplace(sString, '<', ' <', [rfReplaceAll]);
  sString:=StringReplace(sString, '>', '> ', [rfReplaceAll]);
  Result.Text:=StringReplace(sString, ' ', #13#10, [rfReplaceAll]);
  I := 0;
  while I<Result.Count do
    if Trim(Result[I])='' then
    Result.Delete(I)
    else
    begin
    Result[I]:=Trim(Result[I]);
    inc(I);
    end;
  I:=0;
  while I<Result.Count do
  begin
    if (Result[I][1]='<') and (Result[I][Length(Result[I])]<>'>') then
    begin
    J:=I+1;
    while (J<Result.Count) and (Result[J][1]<>'<') and (Result[J][Length(Result[J])]<>'>') do
      inc(J);
    if (J<Result.Count) and (Result[J][1]<>'<') and (Result[J][Length(Result[J])]='>') then
      while J>I do
      begin
        Result[J-1]:=Result[J-1]+' '+Result[J];
        Result.Delete(J);
        dec(J);
      end;
    end;
    inc(I);
  end;
end;

procedure ParseStringList(const StringList: TStringList; const TreeNodes: TTreeNodes; const ParentNode: TTreeNode=nil);
var
  N: TTreeNode;
  SL: TStringList;
begin
  while StringList.Count > 0 do
    if (StringList[0][1]<>'<') and (StringList[0][Length(StringList[0])]<>'>') then
    begin
    if not Assigned(ParentNode) then
      TreeNodes.Add(ParentNode, StringList[0])
    else
      TreeNodes.AddChild(ParentNode, StringList[0]);
    StringList.Delete(0);
    end
    else if (Copy(StringList[0], 1, 2)='</') then
    begin
    if not Assigned(ParentNode) then
      N:=TreeNodes.Add(ParentNode, Copy(StringList[0], 3, Length(StringList[0])-3))
    else
      N:=TreeNodes.AddChild(ParentNode, Copy(StringList[0], 3, Length(StringList[0])-3));
    StringList.Delete(0);
    SL:=TStringList.Create;
    try
      while (StringList.Count > 0) and (StringList[0][1]<>'<') do
      begin
        SL.Add(StringList[0]);
        StringList.Delete(0);
      end;
      ParseStringList(SL, TreeNodes, N);
    finally
      SL.Free;
    end;
    end
    else
    begin
    if not Assigned(ParentNode) then
      N:=TreeNodes.Add(ParentNode, Copy(StringList[0], 2, Length(StringList[0])-2))
    else
      N:=TreeNodes.AddChild(ParentNode, Copy(StringList[0], 2, Length(StringList[0])-2));
    SL:=TStringList.Create;
    try
      while (StringList.Count > 1) and (LowerCase(StringList[1])<>'</'+LowerCase(Copy(StringList[0], 2, Length(StringList[0])))) do
      begin
        SL.Add(StringList[1]);
        StringList.Delete(1);
      end;
      if StringList.Count > 1 then
        StringList.Delete(1);
      ParseStringList(SL, TreeNodes, N);
    finally
      SL.Free;
    end;
    StringList.Delete(0);
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  TreeView1.Items.Clear;
  ParseStringList(ParseString(GetString('C:\Test.txt')), TreeView1.Items);
end;

Suc6

Verwijderd

Topicstarter
Op dinsdag 05 maart 2002 19:17 schreef Ublis het volgende:
PS. Wat inlezen betreft, hoef je ook niet zonodig met Filestreams te spelen (ik ben er zelf doodsbang voor :)).
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
procedure AllesInEen;
var 
  MyTextFile: textfile;
  Woorden: string;
begin
  AssignFile(MyTextFile, 'SomeFileNameAndPath');
  Reset(MyTextFile);
  Readln(MyTextFile, Woorden);  
  CloseFile(MyTextFile);
  Woorden:=Copy(Woorden, Pos('>', Woorden)+1, Length(Woorden));
  Woorden:=Copy(Woorden, 1, Pos('<', Woorden)-1);
  MyLabel.Caption:=Woorden;
end;

Succes ermee.
Meer had ik niet nodig! dit werkt perfect!
Dat andere is wat te lastig, zo bekend ben ik nou ook niet met delphi!

Hee dames en heren, u wordt weer ontzettend bedankt voor de genomen moeite!

Verwijderd

Op woensdag 06 maart 2002 13:24 schreef hvdberg het volgende:

[..]

Waarom doodsbang voor FileStreams? Delphi gebruikt ze zelf ook. Bovendien is bovengenoemde manier de 'ouderwetse' manier.
Nou, 'bang' was ook een beetje overdreven :P. Maar de kwestie is dat ik dingen wel zo eenvoudig mogelijk wil hebben. Hij wilde slechts 1 regeltje inlezen, nota bene nog de eerste in het bestand en die parsen voor 1 elementje met een vaste format. Het boeit de compiler en die bestanden niets of de gebruikte functie al 20 jaar bestaat of dat het de nieuwste creme de la creme is. Het werkt, het is compatibel met alle Delphi (en Turbo-/Free-/ANSI Pascal en naar ik aanneem ook Kylix) versies, hij hoeft als beginner niet te klooien met PChars, StringLists, Creates & Frees, dus waarom niet?

I O+ ReadLn! :9

Verwijderd

Kan je het bestand niet in eem mooi ASCII bestand krijgen zodat je vaste posities hebt die je kunt uitlezen via copy command ?

Zal je een hoop werk schelen als je het in een ASCII kunt krijgen.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 30-08 09:55

Creepy

Tactical Espionage Splatterer

Op woensdag 06 maart 2002 18:35 schreef D32 het volgende:
Kan je het bestand niet in eem mooi ASCII bestand krijgen zodat je vaste posities hebt die je kunt uitlezen via copy command ?

Zal je een hoop werk schelen als je het in een ASCII kunt krijgen.
Wat is het verschil tussen een tekst bestand en een ASCII bestand???

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Niks zolang het bestand maar in columns staat die een vaste breedte en lengte hebben zodat je die kan uitlezen.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 30-08 09:55

Creepy

Tactical Espionage Splatterer

<woord1> woord(en)2 </woord1>
2 vaste dingen waarop je kan gaan zoeken...zoek op </woord>, zoek op <woord2> en copy de rest er tussen uit.. daar heb je echt geen vaste kolommen voor nodig..

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Verwijderd

Topicstarter
code:
1
2
3
  Woorden := Memo4.lines[0];
  Woorden:=Copy(Woorden, Pos('>', Woorden)+1, Length(Woorden));
  Woorden:=Copy(Woorden, 1, Pos('<', Woorden)-1);

Heb gewoon dit stukje genomen en het werkt perfect!

En eventueel dit achter aangeplakt (mocht woord2 met een spatie beginnen namelijk.
code:
1
2
3
  if spatiezoeken = ' ' then
  spatiezoeken := copy (woorden,2,length(woorden))
  else

Na de else geeft het me precies de waarde die ik moet hebben om de files te renamen!
Dit was meer dan genoeg. De waarden in fde eerste regel kunnen wel veranderen en zijn geen vaste kolommen.


Er was ook iets in Delphi waarmee je tekens om kon zetten in cijfers. Ben de naam van de functie kwijt, iemand toevallig? (kun je oa hoofdletters of kleineletter mee omzetten)

Verwijderd

Op donderdag 07 maart 2002 17:12 schreef EM het volgende:

En eventueel dit achter aangeplakt (mocht woord2 met een spatie beginnen namelijk.
Als je de spaties altijd weg wilt hebben, kun je Trim gebruiken; Trim haalt spaties voor én na het woord weg. De laatste coderegel wordt dan:
code:
1
Woorden:=Trim(Copy(Woorden, 1, Pos('<', Woorden)-1));
Er was ook iets in Delphi waarmee je tekens om kon zetten in cijfers. Ben de naam van de functie kwijt, iemand toevallig? (kun je oa hoofdletters of kleineletter mee omzetten)
Een tekst omzetten naar cijfers? StrToInt(MyString) zet een string om naar integer. Als je bedoelt dat je de ASCII-waarde van een Char wilt hebben, kun je Ord(MyChar) gebruiken. Chr(MyByte) doet juist het omgekeerde. Hoofdletters omzetten kan heel mooi met UpperCase(MyString) (maakt hoofdletters) en LowerCase(MyString) (maakt kleine letters).

Als je een MyString='hAxOr sp311iNg' met hoofdletter wilt laten beginnen en vervolgens alleen kleine letters, kun je dit doen:
code:
1
2
MyString := UpperCase(MyString[1]) + 
   LowerCase(Copy(MyString, 2, Length(MyString)));

Verwijderd

Topicstarter
Ord > die zocht ik
Thx! Kun je leuke dingen mee doen! Thx m8!
Pagina: 1