Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.
Toon posts:

[Delphi] String/Text-manipulatie.

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo iedereen.

Voor de achtergrondinformatie, ik heb nooit leren programmeren in Delphi via een tutorial. Ik ben bezig in een boek over C++, om dat degelijk onder de knie te krijgen, maar Delphi heb ik à la trial&error geleerd. Code die ik plaats kan dus eventueel niet optimaal/gestructureerd/.. zijn. Ik gebruik Delphi gewoon kleine applicaties mee te maken als ik even zin heb.
Delphi is que structuur ook nog altijd redelijk verschillend aan C++, dus aan die structuur heb ik niet zoveel.

Anyway,
De laatste tijd ben ik dus een beetje aan het spelen met textmanipulatie. Dit omdat ik het simpelweg leuk vind om mee bezig te zijn, het kan nooit kwaad om te leren.Nu om toch niet zomaar bezig te zijn, bedacht ik een soort van projectje om rond te werken om mezelf meer te leren over textmanipulatie. In de plaats van gewoon text, dacht ik dat het me wel leuk leek om HTML te gaan manipuleren via Delphi, voor als ik bijvoorbeeld op verschillende pagina's eenzelfde iets wil aanpassen. Zo leer ik op een nuttige manier.

Maarnu, deze tekstmanipulatie blijkt bij mij nooit echt goed te werken. Zo probeerde ik iets te maken dat van alle vormen: href="/blablabla.bla", de volledige website toevoegde, zo dus: href="www.blablabla.nl/blablabla.bla". Hiervoor produceerde ik het volgende:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
//Adds the full website name to the tags where needed.
// for PHP files for example
function AddFullSiteName(siteName: string; siteSource: string): string;
begin
siteName := 'www.' + siteName;
while AnsiContainsText(siteSource, 'href=''/') do
  begin
  AnsiReplaceText(siteSource, 'href=''/', ('href=''' + siteName + '/'));
  AnsiReplaceText(siteSource, 'href="/', ('href="' + siteName + '/'));
  end;
result := siteSource
end;


Nu, wanneer ik een website source invoerde, waarbij dit patroon voorkwam, blokkeerde het programma gewoon. De bron van de website word ingevoerd in een Memo, waarvan de inhoud wordt opgeslagen in een string, deze kan vrij lang oplopen. Ik dacht dat het daar aan lag, maar toen ik het testte met de minimum input om het te laten werken, blokkeerde hij ook al. Om het te testen wou ik de bron ingevoerd in de memo onmiddelijk verplaatsen met de nieuwe bron.
Ik roep het zo aan:
Delphi:
1
mmoSiteSource.Text := AddFullSiteName(edtSiteName.Text, mmoSiteSource.Text);


Iemand die weet waar het hier mis gaat?
Ik heb er al over nagedacht om de hele bron in een array van strings te plaatsen, bij het reconstueren van de code zou deze zeer onoverzichtelijk worden, maar dat maakt me atm nog niet veel uit. Het probleem is dat ik geen idee heb hoe ik dat zou doen. 8)7
Stel dat het nu een hele lange source is, (bijvoorbeeld die van de Tweaker.net frontpage, of dergelijke)
zou alles in 1 string plaatsen dan niet verschrikkelijk traag gaan?

Een kleine zet in de juiste richting zou al hard geapprecieerd worden! :)

[Ik heb nog andere dergelijke dingetjes die niet lukken, alles op z'n tijd :| ]

Verwijderd

Ik meen mij te herinneren dat de AnsiReplaceText functie het resultaat van de bewerking teruggeeft via de 'functie result'. Ik kan dit helaas nu even niet controleren, ik zit niet achter Windows.

Wat er dan nu gebeurd is dat de vervanging 'weggegooid' wordt (niet in een variable opslagen), en de loop blijft lopen (tot in de eeuwigheid).

Probeer het volgende eens:

code:
1
2
siteSource := AnsiReplaceText(siteSource, 'href=''/', ('href=''' + siteName + '/')); 
siteSource := AnsiReplaceText(siteSource, 'href="/', ('href="' + siteName + '/'));

  • Megamind
  • Registratie: Augustus 2002
  • Laatst online: 10-09 22:45
Logisch, die AnsiReplaceText geeft een return maar die vang je niet op!

Kijk ook hier eens:
http://www.delphibasics.co.uk/RTL.asp?Name=AnsiReplaceStr

  • Little Penguin
  • Registratie: September 2000
  • Laatst online: 08-06 20:43
Behalve dat je vergeet om de gereturnde waarde terug te plaatsen in SiteSource, vergeet je ook nog op de aanwezigheid van href=" te controleren.

Hieronder een verbeterde versie van AddFullSiteName
Delphi:
1
2
3
4
5
6
7
8
9
10
11
function AddFullSiteName(SiteName: string; SiteSource: string): string;
begin
  SiteName := 'www.' + SiteName; //*
  while AnsiContainsText(SiteSource, 'href=''/')
    or AnsiContainsText(SiteSource, 'href="/') do
  begin
    SiteSource := AnsiReplaceText(SiteSource, 'href=''/', ('href=''' + SiteName + '/'));
    SiteSource := AnsiReplaceText(SiteSource, 'href="/', ('href="' + SiteName + '/'));
  end;
  Result := SiteSource
end;


*: Verder is het nog steeds geen absolute URI, dan moet je er ook nog http:// voor plaatsen.

Verwijderd

Topicstarter
Waarom ben ik daar nu over gelezen?

Ik gebruik de bijgevoegde Borland Help file om functies in op te zoeken. Daar lees ik ook altijd de beschrijvijng. Waarschijnlijk er even niet aan gedacht. :| Waarschijnlijk is dit nu ook het probleem bij de andere dingetjes die niet wouden werken. Ik haalde het omver met de Procedures die ik ook nog gebruik (Delete, Insert,..)

Bedankt! Ook vooral om me er op te wijzen dat ik href=" vergat te controleren. 8)7

Nu kan ik wel weer een eindje verder denk ik!

Verwijderd

Topicstarter
Het hierboven vermelde probleem werkt Perfect!

Mhhh, het andere probleempje blijkt toch nog niet te werken.
dit is het deel waar de n00b-code aan bod komt. :+

Dus;
De bedoeling is om attributen aan te kunnen passen. Tot zo ver heb ik het deel dat het originele attribuut zoekt. Om dat te testen laat ik dat even kopieren en in een overig TEdit plaatsen, zodat ik kan kijken of het werkt. Het verwijderen & inserten van het nieuwe attribuut wordt hierna kinderspel.
Het probleem is dat er niets verschijnt in het TEdit vakje wanneer ik submit.
Hier is de functie die het attribuut zoekt. (ik zal even het method attribuut gebruiken)
[Dit is de eerste keer dat ik mijn code degelijk comment xD]
Delphi:
1
2
3
4
5
6
7
8
9
10
11
function ReplaceActionValue(siteSource: string): string;
var
strIndex, strIndex2, actLength: integer;
midString: string;
begin
strIndex := Pos('method="', siteSource); //Zoek eerste character van method
strIndex2 := PosEx('"', siteSource, (strIndex + 9)); //Zoek de volgende quote
actLength := strIndex - strIndex2; //bereken de lengte van de string ertussen
midString := MidStr(siteSource, (strIndex + 9), actLength); //kopieer het attribuut
result := midString; //return attribuut.
end;

Zo wordt hij aangeroepen: [code="delphi]edtFileDir.Text := ReplaceActionValue(mmoSiteSource.Text);[/code]
[Ik weet dat de code er waarschijnlijk amateuristisch uitziet]
Ditmaal heb ik zeker het resultaat van MidStr opgevangen. Weet niet wat er nu fout is.

Iemand die het ziet?

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 14:26

Creepy

Tactical Espionage Splatterer

Eeeh.. knal eens een breakpoint precies na je begin en ga eens stap voor stap door je code heen lopen (aka debuggen!). Dan kan je precies zien of alles loopt zoals jij verwacht. Je code dumpen en niet aangeven wat je nu zelf al hebt geprobeerd e.d. is hier niet de bedoeling. Eerst zelf aan de slag dus ;)
Gewoon controleren of strIndex, strIndex en actLenght de waardes hebben die je zou verwachten lijkt me zo moeilijk toch niet?

"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
Eens proberen dan maar. :)

  • The Fox NL
  • Registratie: Oktober 2004
  • Laatst online: 14-11 13:17
Wat Creepy zegt, gewoon een breakpoint zetten en dan kijken wat je variabelen voor waarden hebben.

Hint: Ik zou dan eerst eens kijken naar de waarde die actLength krijgt bij jouw berekening.

Je weet hoe je moet debuggen neem ik aan?

Verwijderd

Topicstarter
Ok. Het debuggen lukt ja.

Had de strIndex en strindex2 door elkaar gehaald. Ditmaal krijg ik dus uitvoer in mijn testvakje, maar hier is iets vreemd aan de gang.
Hier is de code die ik nu heb:
[overgeschakeld op action omdat dat meer kan varieren qua lengte]
Delphi:
1
2
3
4
5
6
7
8
9
10
11
function ReplaceActionValue(siteSource: string): string;
var
strIndex, strIndex2, actLength: integer;
midString: string;
begin
strIndex := Pos('action="', siteSource); //Zoek eerste character van method
strIndex2 := PosEx('"', siteSource, (strIndex + 9)); //Zoek de volgende quote
actLength := strIndex2 - strIndex; //bereken de lengte van de string ertussen
midString := MidStr(siteSource, (strIndex + 8), actLength); //kopieer het attribuut
result := midString; //return attribuut.
end;


Ik heb het getest met volgende form bovenkantje:
HTML:
1
<form id="loginform" name="loginform"method="post" action="login.php" style="display: inline;">

dit zou als resultaat 'login.php' moeten geven, right?
Wat ik echter krijg:
login.php" style=
Hij gaat dus een dubbele quote te ver. Tijdens het debuggen heb ik hier op gelet, maar ik kon het niet vinden. Buiten dan dat hij vanaf PosEx al de verkeerde index meekrijgt.

May god know why :|

Verwijderd

Ehmm... Je bent nu bezig zelf een XML parser (of een deel daarvan) te bouwen terwijl je in Delphi uitstekend gebruik kunt maken van de XML parser van Windows zelf. Zoek maar 's op "msxml delphi", en je komt een hoop hits tegen, en een hoop wrappers die 't gemakkelijk maken om nodes, attributes, etc. direct te benaderen en te wijzigen.

't Enige wat je in feite nodig hebt is een import van de type library van MSXML.
Dat doe je via Project -> Import type library... en dan kies je 'Microsoft XML, v6.0 (Version 6.0)'.
Vanaf dat moment kun je prima gebruik maken van Microsoft's eigen XML DOM parser.

Verwijderd

Topicstarter
Wel,
ik zei toch dat ik leerde werken met strings? Dat doe ik nu toch? :)

  • The Fox NL
  • Registratie: Oktober 2004
  • Laatst online: 14-11 13:17
Verwijderd schreef op donderdag 18 september 2008 @ 21:47:
Ehmm... Je bent nu bezig zelf een XML parser (of een deel daarvan) te bouwen terwijl je in Delphi uitstekend gebruik kunt maken van de XML parser van Windows zelf. Zoek maar 's op "msxml delphi", en je komt een hoop hits tegen, en een hoop wrappers die 't gemakkelijk maken om nodes, attributes, etc. direct te benaderen en te wijzigen.

't Enige wat je in feite nodig hebt is een import van de type library van MSXML.
Dat doe je via Project -> Import type library... en dan kies je 'Microsoft XML, v6.0 (Version 6.0)'.
Vanaf dat moment kun je prima gebruik maken van Microsoft's eigen XML DOM parser.
Hoewel ik weet dat het geen mooie html-code is, weet ik niet hoe een xml-parser reageert op <br> constructies (zonder afsluitend element).
Verwijderd schreef op donderdag 18 september 2008 @ 21:38:
...
Hij gaat dus een dubbele quote te ver. Tijdens het debuggen heb ik hier op gelet, maar ik kon het niet vinden. Buiten dan dat hij vanaf PosEx al de verkeerde index meekrijgt.
PosEx geeft geen verkeerde index. Kijk nog maar eens goed tijdens het debuggen naar je actLength. Geeft die wel de goede lengte?

Verder zou ik jou code dit eens laten parsen, dan komt er nog een bug naar boven:
action="" style="display: inline;"

Verwijderd

Topicstarter
Wat is dat toch met mijn logisch denken? Te veel school hier.. :|

Anyway; nu doet ie het wel + Bug fixed:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function ReplaceActionValue(siteSource: string): string;
var
strIndex, strIndex2, actLength: integer;
midString: string;
begin
strIndex := Pos('action="', siteSource); //Zoek eerste character van method
if siteSource[strIndex + 8] <> '"' then  //Als action niet leeg is!
  begin
  strIndex2 := PosEx('" ', siteSource, (strIndex + 9)); //Zoek de volgende quote
  actLength := (strIndex2 - strIndex) - 8; //bereken de lengte van de string ertussen
  midString := MidStr(siteSource, (strIndex + 8), actLength); //kopieer het attribuut
  result := midString; //return attribuut.
  end;
end;


Thanx guys! :)

  • The Fox NL
  • Registratie: Oktober 2004
  • Laatst online: 14-11 13:17
Nog een tip: als je action nu leeg is, dan is het Resultaat niet gedefinieerd. Nu gaat dat zo te zien goed met een string, maar ik zou daar niet van uitgaan. Bij andere types kan het zeker wel fout gaan (dynamische arrays bijvoorbeeld).
Jij kan je probleem beter oplossen door in regel 9 de (strIndex + 9) te vervangen door (strIndex + 8 ). Dan zorg je ervoor dat PosEx begint te zoeken op de eerste positie na je action=".
code:
1
2
3
string: action=""
index:  123456789
                ^=strIndex + 8

Dan kan je dat if statement weghalen.

Dan zit er nog een bug in die het volgende fout laat lopen, maar die mag je zelf zoeken:
action=""style="display: inline;" anderedinges=""

Verwijderd

The Fox NL schreef op donderdag 18 september 2008 @ 21:55:
Hoewel ik weet dat het geen mooie html-code is, weet ik niet hoe een xml-parser reageert op <br> constructies (zonder afsluitend element).
Het was mij niet duidelijk dat 't om niet-XHTML compliant HTML ging (of zelfs dat 't om HTML ging ;) ).

Verwijderd

Topicstarter
The Fox NL schreef op donderdag 18 september 2008 @ 22:26:
Nog een tip: als je action nu leeg is, dan is het Resultaat niet gedefinieerd. Nu gaat dat zo te zien goed met een string, maar ik zou daar niet van uitgaan. Bij andere types kan het zeker wel fout gaan (dynamische arrays bijvoorbeeld).
Jij kan je probleem beter oplossen door in regel 9 de (strIndex + 9) te vervangen door (strIndex + 8 ). Dan zorg je ervoor dat PosEx begint te zoeken op de eerste positie na je action=".
code:
1
2
3
string: action=""
index:  123456789
                ^=strIndex + 8

Dan kan je dat if statement weghalen.

Dan zit er nog een bug in die het volgende fout laat lopen, maar die mag je zelf zoeken:
action=""style="display: inline;" anderedinges=""
Inderdaad :) heb ik overal 8 staan, maar daar nog 9. :+

Op naar de volgende functies! maar ik denk dat ik nu niet gauw meer dergelijk foutjes ga maken. Kan dus wel eventjes zelf verder hoop ik. :)

Bedankt!
Pagina: 1