Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi PChar: Zeichen rechts abschneiden? (https://www.delphipraxis.net/51783-pchar-zeichen-rechts-abschneiden.html)

Pseudemys Nelsoni 18. Aug 2005 18:10


PChar: Zeichen rechts abschneiden?
 
Moin,

wie kann ich einen Teil eines strings (PChars) von rechts abschneiden?`
Angenommen ich habe einen string der so aussieht: 'fhgshsdfhfh....' und ich möchte rechts alle Punkte abschneiden (können beliebig viele sein), wie würde ich das machen? Ich habe mir schon überlegt, eine Schleife rückwärs laufen zu lassen, wo ich den Pointer um 1 dekrementiere... Nur wie lange lass ich die Schleife laufen wenn der String nur Punkte enthält? Auf #0 kann ich ja nicht prüfen.
:oops:

Vielleicht weiss es ja jemand.

marabu 18. Aug 2005 18:17

Re: PChar: Zeichen rechts abschneiden?
 
Hallo Mario,

den Zeiger auf den Anfang deiner Zeichenkette brauchst du schon als Referenzpunkt. Wenn der dekrementierte Zeiger kleiner ist als der Referenzzeiger, dann ist es Zeit aufzuhören...

Grüße vom marabu

dizzy 18. Aug 2005 18:17

Re: PChar: Zeichen rechts abschneiden?
 
Zitat:

Zitat von Pseudemys Nelsoni
Auf #0 kann ich ja nicht prüfen.

Nicht im String, aber lass doch beim Dekrementieren des Pointers noch nen Zähler mitlaufen. Wenn der 0 wird, biste am Ende (bzw. Anfang).

Pseudemys Nelsoni 18. Aug 2005 18:23

Re: PChar: Zeichen rechts abschneiden?
 
Danke Leute :)

@marabu, darf ich denn einfach unter den Index gehen (solange ich da nichts rumschreibe) ?

bigg 18. Aug 2005 18:27

Re: PChar: Zeichen rechts abschneiden?
 
So etwas wie "Ausschneiden" gibt es nicht, wenn du deinen String nur kürzen möchtest,
könntest du SetLength() benutzen ansonsten auch Copy() oder du setzt ein 0 Byte.

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var i, l: Integer;
var s: String;
begin
s := Edit1.Text;

if s <> '' then
begin for i := Length(s) downto 1 do
begin if s[i] <> '.' then
begin
  l := i;
  Break;
end;
end;

SetLength(s, l);
Edit1.Text := s;
end;
end;

Pseudemys Nelsoni 18. Aug 2005 18:30

Re: PChar: Zeichen rechts abschneiden?
 
hallo bigg,

danke für deinen Code ;)

Aber das würde nicht ganz funktionieren, weil ich wie gesagt PChars benutze und weil bei deinem Code bei dem ersten vorkommen von "." gestoppt werden würde, was bei 'text.text2...' ja falsch wäre, da ich ja wie gesagt nur die letzten Punkte löschen will.

marabu 18. Aug 2005 18:35

Re: PChar: Zeichen rechts abschneiden?
 
Zitat:

Zitat von Pseudemys Nelsoni
darf ich denn einfach unter den Index gehen?

Klar doch - mit solchen "wild pointers" erhältst du Zugriff auf andere Variablen oder auf interne Speicherbereiche, die vom Compiler für lokales memory management genutzt werden. Irgendwann schlagen aber die Schutzmechanismen von OS und Hardware zurück und dann ist Schluss mit lustig - AV.

marabu

bigg 18. Aug 2005 18:38

Re: PChar: Zeichen rechts abschneiden?
 
Hast du nicht gesagt, du möchtest von rechts beginned die Punkte abschneiden :!:
Dann sollte es auch so funktionieren.

Pseudemys Nelsoni 18. Aug 2005 18:38

Re: PChar: Zeichen rechts abschneiden?
 
Klingt interessant, könntest du mir das:

Zitat:

Irgendwann schlagen aber die Schutzmechanismen der Hardware zurück und dann ist Schluss mit lustig - AV.
Nochmal näher erklären? Wann würden AVs auftreten?


@bigg: Doch habe ich:

Zitat:

wie kann ich einen Teil eines strings (PChars) von rechts abschneiden?`

XeRo 18. Aug 2005 18:43

Re: PChar: Zeichen rechts abschneiden?
 
hm wie wärs mit einem stringreplace(s,'.','',[rcReplaceAll])?

Pseudemys Nelsoni 18. Aug 2005 18:45

Re: PChar: Zeichen rechts abschneiden?
 
Das würde alle Punkte löschen.

SirThornberry 18. Aug 2005 18:45

Re: PChar: Zeichen rechts abschneiden?
 
wäre aber auch unperformant, außerdem sollen nur die letzten punkte gelöscht werden
Delphi-Quellcode:
procedure RemoveLastDots(AVal: PChar);
var LLen, LLastNoDot: Integer;
begin
  LLen := Length(AVal);
  if LLen > 0 then
  begin
    LLastNoDot := LLen;
    while (LLastNoDot >= 0) and (AVal[LLastNoDot - 1] = '.') do
      dec(LLastNoDot);
    AVal[LLastNoDot] := #0;
  end;
end;
[Edit]Ich seh da grad noch nen Fehler, wird gleich behoben[/Edit]
[Edit2]Gab doch keinen Fehler[/Edit2]

Pseudemys Nelsoni 18. Aug 2005 18:54

Re: PChar: Zeichen rechts abschneiden?
 
Danke SirThornBerry, 1a :D

EDIT: Was passiert eigentlich mit den restlichen Zeichen, wenn ich in einem PChar irgendwo in der mitte einfach ein #0 setze?

SirThornberry 18. Aug 2005 19:06

Re: PChar: Zeichen rechts abschneiden?
 
noch eine variante:
Delphi-Quellcode:
procedure RemoveLastDots(AVal: PChar);
var LMax: PChar;
begin
  LMax := AVal + Length(AVal) - 1;
  while (LMax >= AVal) and (LMax[0] = '.') do
    dec(LMax);
  LMax[1] := #0;
end;

Dax 18. Aug 2005 19:07

Re: PChar: Zeichen rechts abschneiden?
 
Die sind noch da und belegen weiter Speicher, aber #0 als Stringterminator sagt einfach "hier is Ende", und weiter geht der String dann nicht.

SirThornberry 18. Aug 2005 19:22

Re: PChar: Zeichen rechts abschneiden?
 
@dax: das es weiter da ist weiß ich, aber da es um PChar geht bin ich einfach davon ausgegangen das es um 0 terminierte Strings geht.

Dax 18. Aug 2005 19:24

Re: PChar: Zeichen rechts abschneiden?
 
@Sir: Ich bezog mich auf nachfolgendes ;-)
Zitat:

Zitat von Pseudemys Nelsoni
EDIT: Was passiert eigentlich mit den restlichen Zeichen, wenn ich in einem PChar irgendwo in der mitte einfach ein #0 setze?


SirThornberry 18. Aug 2005 19:29

Re: PChar: Zeichen rechts abschneiden?
 
oh, ich hatte nicht gesehen das dort editiert wurde.

Pseudemys Nelsoni 18. Aug 2005 19:54

Re: PChar: Zeichen rechts abschneiden?
 
Danke thornberry,

schoen klein der code und funkt :)

@dax: Ich weiss schon das das #0 "ende" bedeutet ;) nur frag ich mich, wer oder was die restlichen zeichen nachher aus dem string freigibt. hmm... also die nach dem gesetztn #0

marabu 18. Aug 2005 20:14

Re: PChar: Zeichen rechts abschneiden?
 
Zitat:

Zitat von Pseudemys Nelsoni
frag ich mich, wer oder was die restlichen zeichen nachher aus dem string freigibt. hmm... also die nach dem gesetztn #0

Das macht der Code, der den Speicher für deinen String ursprünglich allokiert hat. Der schaut nämlich nicht nach dem von dir eingestreuten #0, sondern nimmt einfach die Größenangabe, die er sich gemerkt hat.

Zitat:

Zitat von Pseudemys Nelsoni
Wann würden AVs auftreten?

Als ich mich noch mit solchen Fragen beschäftigt habe, da gab es eine global bzw. local descriptor table, in der Prozessor und MMU informiert wurden, welche Zugriffe auf welchen Speicher erlaubt sind. Ein Zugriff auf die falschen Adressen sollte vom OS erkannt und gemeldet werden.

marabu

Pseudemys Nelsoni 18. Aug 2005 21:01

Re: PChar: Zeichen rechts abschneiden?
 
Moin Marabu,

das ist mir (noch?) ein bisschen zu hoch, aber nochmal einfach gestellt ;) :

Könnte ein Zugriff auf ein Zeichen VOR dem String je einen Fehler verursachen oder kann ich da immer problemlos drauf zugreifen? Es geht mir nur darum das di Funkktion natürlich keine AVs erzeugt ;)

bigg 18. Aug 2005 21:06

Re: PChar: Zeichen rechts abschneiden?
 
Motzi hat dazu ein Tut geschrieben:
http://www.manuel-poeter.de/index.php?site=tutorials


gruss bigg

Dax 18. Aug 2005 21:06

Re: PChar: Zeichen rechts abschneiden?
 
Ja, kann. Bzw. wird irgendwann garantiert.

marabu 18. Aug 2005 21:29

Re: PChar: Zeichen rechts abschneiden?
 
Zitat:

Zitat von Pseudemys Nelsoni
Könnte ein Zugriff auf ein Zeichen VOR dem String je einen Fehler verursachen oder kann ich da immer problemlos drauf zugreifen?

Auf das Zeichen direkt vor deinem String oder auf irgendein Zeichen davor? Aus technischer Sicht mag die Frage interessieren (direkt davor liegen wahrscheinlich implementierungsbedingte Verwaltungsinformationen für diesen sehr "speziellen" Datentyp von Object Pascal), im Hinblick auf die Code-Qualität ist sie irrelevant. Dein Code darf beim Arbeiten mit Zeigern weder unbeabsichtigt (Fehlerfall), noch bewusst (Erfolg durch Nebenwirkung) auf "solche" Speicherbereiche zugreifen.

marabu

Pseudemys Nelsoni 18. Aug 2005 21:46

Re: PChar: Zeichen rechts abschneiden?
 
@bigg: Guck ich mir an, danke ;)
@Dax: Danke für die Info.

@marabu: auf irgendeinzeichen davor ;) Ich denke ja das wir nichtmehr im string sind wenn wir unter dem ersten zeichen sind oder?

So sah meine Funktion aus, die alle Zeichen links gelöscht hat:

Delphi-Quellcode:
function StripCharsLeft(const S: string; CharSet: TCharSet): string;
var
  PResIdx: PChar;
  PSIdx: PChar;
  Idx: Integer;
  SLen: Integer;
begin
  SetLength(Result, Length(S));
  if S <> '' then
  begin
    PResIdx := @Result[1];
    PSIdx := @S[1];
    Idx := 0;
    SLen := Length(S);
    while (PSIdx^ <> #0) and (PSIdx^ in CharSet) do
    begin
      Inc(PSIdx);
      Inc(Idx);
    end;
    if PSIdx^ <> #0 then
    begin
      CopyMemory(@Result[1], PSIdx, SLen-Idx);
      SetLength(Result, SLen-Idx);
    end;
  end;
end;
Die wollte ich nun nochmal (selbst) so schreiben, das rechts gelöscht wird statt links, aber da wir ja am Anfang des Strings kein #0 Zeichen haben, bin ich daran bis jetzt gescheitert :\

Zitat:

Dein Code darf beim Arbeiten mit Zeigern weder unbeabsichtigt (Fehlerfall), noch bewusst (Erfolg durch Nebenwirkung) auf "solche" Speicherbereiche zugreifen.
Jo, ich dachte nur man darfs, wegen:

Zitat:

Zitat von marabu
Klar doch

Oder war das Ironie?

Danke auch Dir ;)

marabu 19. Aug 2005 06:10

Re: PChar: Zeichen rechts abschneiden?
 
Den scheinbaren Widerspruch in den beiden von mir zitierten Aussagen möchte ich dann doch noch erklären:

Mit "klar doch" wollte ich zum Ausdruck bringen, dass dich der Compiler bei der Programmerstellung nicht daran hindert Zugriffe außerhalb deines strings zu machen. Das ist gewissermaßen die "innere" Sicht. Ich habe ja auch geschrieben, wo du da eventuell landest. Zur Verdeutlichung ein Stück Code aus vergangenen Zeiten:

Delphi-Quellcode:
function AllocString(size: cardinal): PChar;
var
  pCard: ^Cardinal;
begin
  pCard := AllocMem(size + 2 * SizeOf(Cardinal));
  pCard^ := size;
  Inc(pCard);
  pCard^ := 0; // length
  Inc(pCard);
  Result := Pointer(pCard);
end;
In meinem späteren Beitrag habe ich die "äußere" Sichtweise eingenommen. Die Funktionen zum Umgang mit sz-strings und big strings basieren auf Konventionen - nach dem terminierenden #0 ist der string zu Ende und vor dem string liegender Speicher ist tabu. Man hält sich daran oder man weiß ganz genau was man da tut. Klar, dass systemnahes Programmieren mitunter auch zu implementationsabhängigem Code führen kann. Du solltest sowas aber weitgehend vermeiden.

Viel Spaß noch beim Arbeiten mit Zeigern.

marabu

PS: hast du der Schildkröte ein i geklaut oder ist das ein falscher Verdacht von mir?

Olli 19. Aug 2005 08:44

Re: PChar: Zeichen rechts abschneiden?
 
Zitat:

Zitat von marabu
Als ich mich noch mit solchen Fragen beschäftigt habe, da gab es eine global bzw. local descriptor table, in der Prozessor und MMU informiert wurden, welche Zugriffe auf welchen Speicher erlaubt sind. Ein Zugriff auf die falschen Adressen sollte vom OS erkannt und gemeldet werden.

LDT und GDT gibt es immernoch, und ja, die werden je nach Threadkontext anders geladen. So ist beispielsweise der TEB (Thread Environment Block) immer an einer anderen Stelle pro Thread, man kann ihn aber ermitteln, indem man fs:0 ausliest. Voila, ein Deskriptor ganz nach altem PM-Stil ;)
Im PM sagt man zu cs, ds, es, fs usw. ja nicht umsonst "Segment-Deskriptoren", obwohl es doch keine Segmente mehr gibt :zwinker:

Zitat:

Zitat von Pseudemys Nelsoni
Könnte ein Zugriff auf ein Zeichen VOR dem String je einen Fehler verursachen oder kann ich da immer problemlos drauf zugreifen? Es geht mir nur darum das di Funkktion natürlich keine AVs erzeugt ;)

Egal wo, ja. Das Problem ist folgendes:
  • Jeder Prozeß hat insgesamt 2 GB, die ihm gehören (die anderen 2 bis 4 sind "Kernelspeicher", kann aber auch verstellt werden, zB auf Servern)
  • Wie kann ein Prozeß 2 GB haben wenn dein PC nur 1 GB hat?
  • Es ist kein echter sondern virtueller Speicher (Linearer Speicher). Auf den echten kannst du aus dem Usermode nicht (ohne weiteres) zugreifen.
  • Dieser Speicher wird in Tabellen vom OS verwaltet, welches dann dafür sorgt, daß lineare zu physikalischen Seiten gemappt werden können.
  • Zugriff wird vom OS immer überprüft und wenn du woanders zugreifst als du alloziert hast, gibt's normalerweise eine Exception (auch die kann man bekanntlich abfangen)
Fazit: Laß es sein. Wenn du sowas mit Exceptions machen willst, schau dir an wie zB Stacks implementiert werden. Ansonsten ist Speicher den man nicht alloziert hat tabu. Und mit "man" meine ich hier einen beliebigen Teil deines Programmes (oder von außen einen Teil der als dein Programm agiert).
Hinweis: manche Stacks sind so implementiert, daß sie wachsen wenn eine Exception ausgelöst wurde. In diesem Fall wird die Exception vor dem Programm versteckt und intern genutzt um den Stack dynamisch zu vergrößern. Ich persönlich benutze das gerade für ein speichersparendes Modell von Molekülen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:46 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz