Jak podzielony tekst zapisać do Tablicy?

0

Witam, czy wie ktoś jak zapisać string podzielony przecinkami do tablicy?

Np.:

for I := 1 to 64 do
      begin
        ExtractStrings([','], [' '], PChar(S), Output[I]);
      end;

Oczywiście kod nie zadziała, ale zobrazuje co chcę osiągnąć.

dodanie znacznika <code class="delphi"> - fp

1
var Output:TStringList;
...
Output:=TStringList.Create;
ExtractStrings([','],[' '],PChar(S),Output);
for I:=0 to Output.Count-1 do
begin
  Output[I];
end;
0

Dzięki za szybką odpowiedź.
Wyskakuje błąd w

for I:=0 to Length(Output)-1 do

E2008 Incompatible types

0

Dzięki wielkie! Działa jak zawsze....
Tylko jeszcze jedno pytanko, jak w trakcie działania programu wyczyścić zawartość TStringList, tak aby TStringList.Count wskazał 0, ale abym mógł później ponownie coś do niego "wsadzić"?

0

RTFM!

TStringList.Clear;
0

Nie działa, próbowałem.....

0

Co to znaczy "nie działa"? Musi działać.
Coś robisz źle, pokaż kod.

0

Dobra, działa, jak zwykle nie dopatrzyłem i chciałem wykonać ExtractStrings na pustym już TStringList i wywalało mi - Ten program nie odpowiada.

A czy zna ktoś może sposób, jak przekazać TStringList jako parametr funkcji/procedury? Czy jest taka możliwość w ogóle? Bo mi wywala błąd(Program nie nagle przestał działać)......

procedure Parser(C : String; P : TStringList);
begin
  Writeln('C= ' + C);
  Readln;
  Writeln('P= ' + P.Strings[0]); <-- W tym miejscy wywala błąd
  Readln;
end;

Próbowałem na wiele sposobów, nawet P.Text. Parametr dla C dochodzi normalnie.
Dodam jeszcze że procedura jest umieszczona w bibliotece DLL.

0

A czy zna ktoś może sposób, jak przekazać TStringList jako parametr funkcji/procedury?

Najzwyczajniej, jak inny parametr:

uses
  Classes;

  procedure Foo(Bald: TStringList);
  begin
    Bald.Add('second');
    Bald.Add('third');
  end;

var
  slFoo: TStringList;
begin
  slFoo := TStringList.Create();
  try
    slFoo.Add('first');
    WriteLn('Before: ', slFoo.Count);

    Foo(slFoo);
    WriteLn('After:  ', slFoo.Count);
  finally
    slFoo.Free();
    ReadLn;
  end;
end.

wynik:

Before: 1
After:  3

EDIT: Teraz dopiero zauważyłem, że chodzi o bibliotekę dll... W takim razie może być z tym problem; Do bibliotek bezpieczniej jest przekazywać typ PChar - zwykłe String sprawiają problemy (to jeśli chodzi o przekazywanie w parametrze właściwości StringList.Text);

Jeśli chodzi o środowisko Delphi7, to w kodzie biblioteki masz komunikat w postaci komentarza:

{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }

więc zastosuj się do niego;

Jeśli natomiast masz inne środowisko - nowsze Delphi czy Lazarusa - poszukaj w sieci; Na pewno już ktoś kiedyś miał z tym problem.

0

Dodam jeszcze że procedura jest umieszczona w bibliotece DLL.

W związku z wieloma sprawami typowo internalsowymi, w które nie zamierzam się wgłębiać, powiem tylko, że masz dwa rozwiązania:
1.Jako pierwszy moduł w bibliotece oraz projekcie ustaw ShareMem.
2.Korzystaj z PChar-ów, ShortString-ów lub tablic (z tym, że tablice to takie bardziej "ultra hardcore" rozwiązanie :P PChar jest bardziej przyziemny i najczęściej wykorzystywany).

0

Dobra poradziłem sobie. Teraz mam pytanie trochę z innej beczki. A więc, robię Interpreter własnego "języka"(niekompilowany). (Wiem, głupie, ale się wciągnąłem mimo że już kolejny raz piszę od nowa).
I mam pytanie odnośnie tego, czy mógłby mi ktoś poradzić jak zrobić obsługę zmiennych środowiskowych? Bo z tego co wiem, to w Delphi nie można deklarować zmiennych dynamicznych.
Pomyślałem żeby zrobić to przez TStringList, ale nie opanowałem go na tyle dobrze aby wynajdować zmienne po samej nazwie, czy nawet kasować poszczególne.

P.S. Proszę o wyrozumiałość

1
Maestro69pw napisał(a):

... ale nie opanowałem go na tyle dobrze aby wynajdować zmienne po samej nazwie, czy nawet kasować poszczególne.

O tak to potężny kawał wiedzy tajemnej!

List.Values['ala']:='ma kota';
0

I mam pytanie odnośnie tego, czy mógłby mi ktoś poradzić jak zrobić obsługę zmiennych środowiskowych?

Pisane z palca:

Type TSymbolType = (stType, stFunction, stVariable, stConstant, ...);

Type TSymbol = Class // "fizyczny symbol"
 Private
  fType: TSymbolType;
  fName: String;
  fToken: PToken; // weź pod uwagę, że musi to być wskaźnik na token, a nie sam rekord/klasa

 Public
  Constructor TSymbol.Create(Typ: TSymbolType; Name: String; Token: PToken);
  
  Property Name: String read fName; // zasadniczo nazwa symbolu (np.zmiennej/klasy/typu/wtf) nie powinna być modyfikowana, gdy już jest ustalona, stąd jest to read-only.
  Property Token: PToken read fToken; // j/w
 End;
 
Type TSymbolList = TList<TSymbol>; // lista symbolów (np.zadeklarowanych zmiennych), używana np.w funkcji:

(*
 Type TFunction = Class(TSymbol)
  Private
   { ... }
   SymbolList: TSymbolList;
   { ... }
  End;
*)

{ ... }

Type TVariable = Class;

{ ... }

Type TReadEvent = Function(const Variable: TVariable): Variant;
Type TWriteEvent = Procedure(const Variable: TVariable; const Value: Variant);

Type TVariable = Class(TSymbol) // pojedyncza zmienna
 Private
  fType: TVariableType; // bool/char/int/float/string i co tam jeszcze tylko masz
  fRange: TRange; // blok, w którym zmienna jest widzialna (tyczy się wyłącznie zmiennych lokalnych, no, chyba, że masz klasy/przestrzenie nazw i/lub pozwalasz na bloki poza funkcjami (czyli np."begin..end" poza jakąś funkcją) :P)
  
  fValue: Variant; // używane, gdy 'fOnRead' oraz 'fOnWrite' są równe 'nil', jest to właściwa wartość zmiennej

  fOnRead: TReadEvent;
  fOnWrite: TWriteEvent;

  Function getValue: Variant;
  Procedure setValue(const Value: Variant);

 Public
  Constructor Create(Name: String; Token: PToken; Typ: TVariableType; onRead: TReadEvent; onWrite: TWriteEvent);

  Property Value: Variant read getValue write setValue;
  Property Typ: TVariableType read fType;
End;

(* TSymbol.Create *)
Constructor TSymbol.Create(Typ: TSymbolType; Name: String; Token: PToken);
Begin
 fType := Typ;
 fName := Name;
 fToken := Token;
End;

(* TVariable.Create *)
Constructor TVariable.Create(Name: String; Token: PToken; Typ: TVariableType; onRead: TReadEvent; onWrite: TWriteEvent);
Begin
 inherited Create(stVariable, Name, Token);
 
 fType := Typ;
 fOnRead := onRead;
 fOnWrite := onWrite;
End;

(* TVariable.getValue *)
Function TVariable.getValue: Variant;
Begin
 if (fOnRead = nil) Then
  Exit(fValue) Else
  Exit(fOnRead(self));
End;

(* TVariable.setVaule *)
Procedure TVariable.setValue(const Value: Variant);
Begin
 if (fOnWrite = nil) Then
  fValue := Value Else
  fOnWrite(self, Value);
End;

{ ... }

// EnvVarRead
Function EnvVarRead(const Variable: TVariable): Variant;
Begin
 Result := GetEnvVarValue(Variable.Name); // patrz link do artykułu powyżej
End;

// EnvVarWrite
Procedure EnvVarWrite(const Variable: TVariable; const Value: Variant);
Begin
 SetEnvVarValue(Variable.Name, Value); // patrz link do artykułu powyżej
End;

{ ... }

// FetchEnvironmentVariableList
Function FetchEnvironmentVariableList: TStringList;
Begin
 Result := TStringList.Create;
 // to sobie napisz na podstawie funkcji "GetAllEnvVars" z artykułu: http://www.delphidabbler.com/articles?article=6
End;

// BeforeParse
Procedure BeforeParse;
Var EnvList: TStringList;
    Tmp: String;
Begin
 // AddGlobalVar(DeclToken: PToken; VarName: String; onRead: TReadEvent; onWrite: TWriteEvent);

 Try
  EnvList := FetchEnvironmentList;
  For Tmp in EnvList Do
   AddGlobalVar(nil, Tmp, EnvVarRead, EnvVarWrite);
 Finally
  EnvList.Free;
 End;
End;

Jakoś tak to wyglądałoby (oczywiście w uproszczeniu), nie wiem jak Twój parser wygląda od strony budowy, stąd tyle kodu :P

Bo z tego co wiem, to w Delphi nie można deklarować zmiennych dynamicznych.

Zależy, co masz na myśli. Są typy generyczne...


Btw, kompilatory są znacznie fajniejsze od parserów zarówno w pisaniu, jak i działaniu ;>
0

Dzięki wielki wszystkim za pomoc!
@Patryk27 - próbowałem użyć tego co mi napisałeś, ale chyba mnie to przerosło.....

Zamiast tego zrobiłem coś takiego:

type
  TVarMgr = class
  private
    VarStore : TStringList;
  public
    constructor Create;
    function Add(N : String; V : String) : Boolean;
    function Delete(N : String) : Boolean;
    function Edit(N : String; V : String) : Boolean;
    function Load(N : String) : String;
    function List : String;
    function VarExists(N : String) : Boolean;
end;

constructor TVarMgr.Create;
begin
  VarStore := TStringList.Create;
end;

function TVarMgr.Add;
begin
  if not VarExists(N) then
  begin
    VarStore.Add(N + '=' + V);
    if VarExists(N) then if Load(N) = V then Result := True else Result := False;
    if not VarExists(N) then Result := False;
  end;
  if VarExists(N) then Result := False;
end;

function TVarMgr.Delete;
begin
  if VarExists(N) then
  begin
    VarStore.Values[N] := '';
    if not VarExists(N) then Result := True
      else Result := False;
  end;
  if VarExists(N) then

end;

function TVarMgr.Edit;
begin
  if VarExists(N) then
  begin
    VarStore.Values[N] := V;
    if Load(N) = V then Result := True
      else Result := False;
  end;
  if not VarExists(N) then Result := False;
  
end;

function TVarMgr.Load;
var
  S : String;
begin
  Result := VarStore.Values[N];
end;

function TVarMgr.VarExists;
begin
  if VarStore.Values[N] = '' then Result := False;
  if VarStore.Values[N] <> '' then Result := True;
end;

function TVarMgr.List;
begin
  Result := VarStore.Text;
end;

end.

Może macie dla mnie jakieś rady? Co tu można ulepszyć(ale tak, by nie było zbyt skomplikowane)?

0

Co tu można ulepszyć(ale tak, by nie było zbyt skomplikowane)?

Jeżeli korzystasz z nowszego Delphi z obsługą generyków:
1.Zrób klasę TVariable, która będzie posiadała dwa pola typu String: jej nazwę oraz wartość.
2.Zamiast VarStore : TStringList; zrób wtedy VarList: TList<TVariable>;
lub
1.Zrób TMap<String, String>; (mapę nazwa zmiennej -> jej wartość).
To tak na początek.
Jeżeli posiadasz stare Delphi bez obsługi generyków: pobierz Lazarusa i idź do punktu pierwszego korzystając ze TFPGList/TFPGMap.


A tak bardziej odnośnie kodu: ```delphi function TVarMgr.Add; begin if (VarExists(N)) Then Exit(False);

VarStore.Add(N+'='+V);
Exit(True);
end;


```delphi
function TVarMgr.Delete;
var Index: int32;
begin
  Index := VarStore.IndexOf(N);
  if (Index > -1) Then
  Begin
   VarStore.Delete(Index);
   Result := True;
  End Else
   Result := False;
end;
function TVarMgr.VarExists; {inline;}
begin
  Result := (VarStore.IndexOf(N) > -1);
end;

In fact, w ogóle się do tego zabierasz tak od przysłowiowej d*py strony...

0
  1. Add i Edit czym mają się różnić? Czyli wystarczy: VarStore.Values[N]:=V;
  2. Delete: VarStore.Delete(VarStore.IndexOfName(N));
  3. Load: V:=VarStore.Values[N];
  4. VarExists: VarStore.IndexOfName(N)>=0
  5. List: VarStore.Text;

Akurat tu klasy nie potrzebujesz.

0

Dobra zastosowałem to co mi napisaliście. Ale mam inny problem bo nie wiem jak zrobić coś takiego:

if WARTOŚĆ <> LISTA W TSTRINGLIST then ......

Bo robię analizator składniowy i mam listę komend zapisaną w TStringList które obsługuje interpreter. I potrzebuję porównać, czy aktualna komenda jest na liście, jeśli nie to wywali błąd. Wiem, może proste, może nie, ale jakoś już siedzę z tym od wczoraj i wciąż nie mogę dojść jak to zrobić. Próbowałem dziesiątki sposobów, ale nadal nie wychodzi.

1

Metoda IndexOf dla TStringList. Nieważna wielkość liter, zwraca -1 kiedy danego tekstu nie ma na liście.

1

I potrzebuję porównać, czy aktualna komenda jest na liście, jeśli nie to wywali błąd.

Jeśli masz "komendę" jako łańcuch np. AnsiString i w liście masz zapisane wszystkie "komendy", to możesz wykorzystać metodę IndexOf, która zwraca indeks znalezionej pozycji; Jeśli nie znaleziono - zwraca -1:

var
  slCommands: TStringList; //lista komend
  intIndex: Integer;       //indeks szukanej komendy w liście
  {...}
begin
  {...}

  //szukanie komendy na liście
  intIndex := slCommands.IndexOf(strCommand);

  //sprawdzenie czy znaleziono
  if intIndex = -1 then
    //wyświetlenie błędu bo nie znaleziono
  else
    //kontynuacja programu - komendę znaleziono
0

Wielkie dzięki, już obczajam....

Znacie może sposób aby delphi tworzyło aplikacje dla samego Windows'a, a nie dla .NET? Prościej, czy jest możliwość tworzenia aplikacji nieuzależnionych od platformy .NET Framework w Delphi(właściwie to Embarcadero RAD Studio XE)? I czy będę wtedy musiał korzystać tylko z WinApi, czy VCL jest niezależne od .NET?

0

A jakie masz opcje do wyboru przy tworzeniu nowego projektu? Na pewno jest tam podział na zwykłą aplikację okienkową i pod .NET - sprawdź;

Jeśli nie będziesz chciał pisać pod dotNeta, to nie musisz wszystkiego pisać za pomocą jedynie WinAPI - do dyspozycji na pewno będzie standardowy VCL i RTL, taki jak w innych - starszych wersjach środowiska, więc z WinAPI w ogóle nie będziesz musiał korzystać.

0

Właśnie sprawdzałem, mam jedynie takie platformy: Windows 32-bit, Windows 64-bit, OS-X, iOS Device, iOS Simulator. Hmm, nie wiem muszę więcej poszperać na internecie...
A tak z innej beczki, wiesz może jak zrobić odwrotną pętlę for? Np.

for I := 200 to 0 do Writeln('Linia :' + IntToStr(I));
1
Juby_PW napisał(a)

A tak z innej beczki, wiesz może jak zrobić odwrotną pętlę for?

O.o

for I := 200 downto 0 do
  Writeln('Linia :', I);

Coś mi się widzi, że nie bardzo znasz podstawy pascala...

0

Shiiit! A ja widziałem to w sekcji Słowa Kluczowe i pomyślałem że to obniża liczbę o podaną wartość....
No nic, kolejny raz dziękuję!

1 użytkowników online, w tym zalogowanych: 0, gości: 1