Avatar billede kennethv Nybegynder
06. maj 2010 - 14:46 Der er 4 kommentarer og
1 løsning

Finde tekst på et bestemt sted

Jeg en function som skal finde noget tekst på et bestem sted.

Jeg har så dette:

Function TfrmLDAP.FindOU(SourceList: TStringList;Key: String): String;
var
  List, LineList: TStringList;
  I, x: Integer;
begin
  result := '';
  List := TStringList.Create;
  List := SourceList;
  try
    for I := 0 to List.Count - 1 do
    begin
      LineList := TStringList.Create;
      LineList.Delimiter := ';';
      LineList.CaseSensitive := True;
      try
        LineList.DelimitedText := List[I];
        x := LineList.IndexOf(Key);
        if x > -1 then
        begin
          result := LineList[x-1];
          break;
        end;
      finally
        LineList.Free;
      end;
    end;
  finally
    List.Free;
  end;
end;


procedure TfrmLDAP.BitBtn1Click(Sender: TObject);
var OUSite,temp : string; i : integer;
begin
  if (lbCountry.ItemIndex <> -1) and (lbSite.itemIndex <> -1)  then
  begin
    OUSite := FindOU(strSiteList,lbSite.Items[lbSite.itemindex]);
  end;
end;

Indholdet af strSiteList er:
Common;
ES;Sweden
GO;Sweden Göteborg
LU;Sweden  Lund
LX;Test site Tumba
OR;Sweden Örebro
RO;Sweden  Ronneby
SC;Sweden  Tumba sales company
SU;Sweden Sundsvall
TU;Sweden  Tumba


Indhold af Key er:
Sweden  Tumba

Når den har kørt min FindOU er result = ''

Jeg forstår det ikke.

Nogen der kan hjælpe?
Avatar billede martinlind Nybegynder
06. maj 2010 - 17:48 #1
kan ikke rigtig huske det, men mener stringlist indexof ikke er så god til at finde del-strenge, brug pos/posEx i stedet for :-)
Avatar billede hrc Mester
06. maj 2010 - 19:31 #2
Martin: Du har ret, IndexOf kigger på strengen. Pos og PosEx (StrUtils) er bedre. Endnu bedre var det at smide data som et objekt pi en TObjectList (ContNrs) (jeg gentager mig selv, men her er det helt oplagt)

Derfor:

Jeg plejer at vakle mellem to løsninger:
- At opbevare objekterne parallelt i en TObjectList. Fordelen er, at når denne frigives, så ryger alle dataobjekterne også. En anden er at det er let at vedligeholde. Ulempen er at koden fylder en smule mere.
- Kun have objekterne i listen. Så må disse oprettes i formens constructor (OnCreate) og frigives i destructoren (OnDestroy)

Kan bedst lide den første da indkapslingen er bedst og man kan indbygge ind- og udlæsning her. Her kommer denne løsning:

type
  TNameData = class
  private
  public
    constructor Create(aReader: TReader); overload; // Indl. fra fil
    constructor Create(const aInit, aCountry, aTown: string); overload; // Ny
    property Init: string read fInit;
    property Country: string read fCountry;
    property Town: string read fTown;

    procedure WriteData(aWriter: TWriter);
  end;

  TNameList = class(TObjectList)
  private
    function GetItems(const aIndex: integer): TNameData;
  public
    property Items[const aIndex: integer]: TNameData read GetItems; default;
    procedure LoadData;
    procedure SaveData;
   
    IndexOfInit(aInit: string): integer;
    IndexOfCountry(aCountry: string): integer;
    IndexOfTown(aTown: string): integer;
    FillStrings(aStrings: TStrings);
  end;

  TForm1 = class(TForm)
  private
    fNameList: TNameList;
  public
  end;

..

constructor TForm1.OnCreate(Sender: TObject);
var
  i: integer;
begin
  fNameList := TNameList.Create;
  fNameList.LoadData;
 
  fNameList.FillStings(ComboBox.Items);
end;

destructor TForm1.Destroy;
begin
  ComboBox.Items.Clear; // Events can be triggered, better clear before freeing
  fNameList.Free;
end;

...
 
constructor TNameData.Create(const aInit, aCountry, aTown: string);
begin
  inherited Create;
  fInit := UpperCase(trim(aInit));
  fCountry := UpperCase(trim(aCountry));
  fTown := UpperCase(trim(aTown));
end;

constructor TNameData.Create(aReader: TReader);
begin
  inherited Create;
  fInit := aReader.ReadString;
  fCountry := aReader.ReadString;
  fTown := aReader.ReadString;
end;

procedure TNameData.WriteData(aWriter: TWriter);
begin
  aWriter.WriteString(fInit);
  aWriter.WriteString(fCountry);
  aWriter.WriteString(fTown);
  aWriter.FlushBuffer; // Sync stream.
end;

...

const
  DataFilename = 'c:\test.dat';

procedure TNameList.LoadData;
var
  Stream: TFileStream;
  Reader: TReader;
begin
  if not FileExists(DataFilename) then
    exit;

  Stream := TFileStream.Create(DataFilename,fmOpenRead);
  Reader := TReader.Create(Stream,1024);
  BeginUpdate;
  try
    Clear;
    while Stream.Position < Stream.Size do
      Add(TNameData.Create(Reader));

    // - en lidt simplere måde at indlæse på
    // Add(TNameData.Create('','',''));
    // Add(TNameData.Create('','',''));
    // Add(TNameData.Create('','',''));
  finally
    Reader.Free;
    Stream.Free;
    EndUpdate;
  end;
end;

procedure TNameList.SaveData;
var
  Stream: TFileStream;
  Writer: TWriter;
begin
  Stream := TFileStream.Create(DataFilename,fmCreate);
  Writer := TWriter.Create(Stream,1024);
  try
    for i := 0 to Count - 1 do
      Items[i].WriteData(Writer);
    Writer.FlushBuffer; // Sync again (to be sure)
  finally
    Writer.Free;
    Stream.Free;
  end;
end;

function TNameList.GetItems(const aIndex: integer): TNameData;
begin
  result := inherited Items[aIndex] as TNameData;
end;

procedure TNameList.FillStrings(aStrings: TStrings);
var
  i: integer;
  NameData: TNameData;
begin
  aStrings.BeginUpdate;
  try
    aStrings.Clear;
    for i := 0 to Count - 1 do
    begin
      NameData := Items[i];
      aStrings.AddObject(NameData.ToString,NameData);
    end;
  finally
    aStrings.EndUpdate;
  end;
end;

function TNameList.IndexOfInit(aInit: string): integer;
var
  Found: boolean;
begin
  result := -1; // not found
  while (result < Count - 1) and not Found do
  begin
    inc(result);
    Found := SameText(Items[i].Init,aInit);
  end;
  if not Found then
    result := -1;
end;

function TNameList.IndexOfCountry(aCountry: string): integer;
var
  Found: boolean;
begin
  result := -1; // not found
  while (result < Count - 1) and not Found do
  begin
    inc(result);
    Found := SameText(Items[i].Country,aCountry);
  end;
  if not Found then
    result := -1;
end;

function TNameList.IndexOfTown(aTown: string): integer;
var
  Found: boolean;
begin
  result := -1; // not found
  while (result < Count - 1) and not Found do
  begin
    inc(result);
    Found := SameText(Items[i].Town,aTown);
  end;
  if not Found then
    result := -1;
end;

Det kan godt være det fylder lidt, men det jeg har lavet her er 90% af det jeg mener er den rigtige løsning (nedarving fra TPersistent eller ej). De data du skitserer bør splittes op i en en klasse der indeholder hvert element. Viser også hvordan man laver overloadede metoder og hvordan man flytter funktionaliteten ned i de lag som ved hvordan de skal håndteres (WriteData(aWriter: TWriter), eksempelvis).

Det er skrevet i et stykke da det er noget jeg har brugt mange gange - slåfejl kan ikke udelukkes
Avatar billede hrc Mester
06. maj 2010 - 20:13 #3
Glemte lige TNameData.ToString: string; override; Normalt returnerer den klassens navn, men jeg brugte altså funktionen før det kom på i D2007

function TNameData.ToString: string;
begin
  result := format('%s: %s, %s',[fInit, fCountry, fTown]);
end;
Avatar billede kennethv Nybegynder
07. maj 2010 - 09:37 #4
Wow, det ser ganske cool ud, men jeg tror at jeg har fundet løsningen.

Den er, at den function jeg har dropper jeg helt. For jeg fandt ud af at denne klare det for mig.

procedure TfrmLDAP.AddToSiteList(disp: IADs);
var adOU : IADsOU; Descr, OUName: string;
begin
  ADsGetObject(Disp.ADsPath, IADsOU, adOU);
  Descr := GetProp(adOU,'Description');
  OUName := GetProp(adOU,'Name');
  Descr := copy(Descr,pos(',',Descr)+1,length(descr));
  if Descr <> '' then
    lbSite.Items.Add(Descr);
  strSiteList.Values[Descr] := OUName;
end;

procedure TfrmLDAP.BitBtn1Click(Sender: TObject);
var OUSite,temp : string; i : integer;
begin
  if (lbCountry.ItemIndex <> -1) and (lbSite.itemIndex <> -1)  then
  begin
    OUSite := strSiteList.Values[lbSite.Items[lbSite.itemindex]];
  end;
end;
Avatar billede hrc Mester
07. maj 2010 - 09:44 #5
Nå, det var AD du havde gang i.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester