Funkcja StringReplace() nie działa

0

Witam,

mam problem w jednej kolumnie z funkcją StringReplace(). W trzech różnych kolumnach mam liczby zapisane w taki sposób, np.:

2 000 600
2 000 m
1 400

Aby móc dokonać konwersji StrToInt muszę pozbyć się zbędnych spacji i literki 'm' (jeżeli występuje na końcu). W dwóch kolumnach rozwiązałam ten problem za pomocą kodu (kod dla jednej z kolumn):

for i:=1 to StringGrid1.RowCount-1 do
  begin
        d := StringGrid1.Cells[4,i];
        if d[Length(d)] = 'm' then
        begin
        p := Cut(d, Length(d)-2);
        StringGrid1.Cells[4,i] := p;
        m := StringReplace(p, ' ', '', [rfReplaceAll]);
        StringGrid1.Cells[4,i] := m;
        end
        else
        begin
        m := StringReplace(d, ' ', '', [rfReplaceAll]);
        StringGrid1.Cells[4,i] := m;
        end;
  end;

I wszystko cacy. W trzeciej kolumnie liczby występują tylko ze spacjami w środku (nie ma przypadku, że 'm' jest na końcu), więc próbuję to rozwiązać w analogiczny sposób:

for i:=1 to StringGrid1.RowCount-1 do
  begin
        d := StringGrid1.Cells[1,i];
        m := StringReplace(d, ' ', '', [rfReplaceAll]);
        StringGrid1.Cells[4,i] := m;
  end;

Niestety bezskutecznie. Nie mam pojęcia dlaczego, ale program w ogóle nie odnajduje w tej kolumnie spacji. Jeżeli próbuję ją zamienić na jakikolwiek znak, to nic się nie zmienia. A jeśli np. próbuję zmienić wszystkie zera na 'x' to już działa.

Czy ktoś wie dlaczego tak jest? Co jest nie tak?

2

Bo tam jest spacja niepodzielna, #$A0 jeżeli się nie mylę.

0

Hmm... i co w takiej sytuacji? Jak mam pozbyć się tych spacji aby móc uzyskać typ Integer?

0

Niestety ani #$0A ani #$160 nie działa...

W kodzie HTML spacja ta oznaczona jest &nbsp. Znalazłam gdzieś na jakiejś stronie odpowiednik jako #$160, ale nie działa :(

1

Spróbuj:

 StringReplace(d, ' ', '', [rfReplaceAll, rfIgnoreCase]); 

Ewentualnie

 StringReplace(Trim(d), ' ', '', [rfReplaceAll, rfIgnoreCase]); 
2

Możesz sobie wypisać listę znaków w stringu wraz z odpowiednikami w ascii (chyba, że to unicode to nie wiem czy ten kod zadziała):
Na formie umieść memo

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
  d: string;
begin
  d := 'test';
  for i:=1 to Length(d) do
    Memo1.Lines.Add(d[i] + ' = ' + IntToStr(Ord(d[i])));
end;
1

Użyj debugiera, ustaw breakpoint za instrukcją:

m := StringReplace(p, ' ', '', [rfReplaceAll]);

Oraz ustaw podglądanie wartości m
I naciskaj <run> dopóki nie zauważysz że masz w m tą spację.
Po czym policz ręcznie numer znaku i podświetl poprzez <Ctrl-F7>: Ord(m[2]), zamiast 2 - numer znaku

1

Nie wiem w czym tak duży problem, ale muszę Cię zmartwić @madzieq - funkcja StringReplace działa :]

W pierwszej kolejności trzeba usunąć znaki separatora (tu: spacji), następnie znaleźć ostatnią cyferkę w ciągu wejściowym, a na koniec skopiować samą liczbę z ciągu i ją przekonwertować; Wystarczy poniższa funkcja:

function ConvertStringToInt(AValue: AnsiString; ADefault: Integer): Integer;
var
  intLastDigitIdx: Integer;
begin
  AValue := StringReplace(AValue, ' ', '', [rfReplaceAll]);
  intLastDigitIdx := Length(AValue);

  while (intLastDigitIdx > 0) and not (AValue[intLastDigitIdx] in ['0' .. '9']) do
    Dec(intLastDigitIdx);

  Result := StrToIntDef(Copy(AValue, 1, intLastDigitIdx), ADefault);
end;

Usuwa ona wszystkie znaki spacji z ciągu oraz pomija jakiekolwiek nieliczbowe podciągi z końca łańcucha wejściowego; Przykładowe użycie:

const
  SOME_VALUE = '2 000 600 m';
var
  intValue: Integer;
begin
  intValue := ConvertStringToInt(SOME_VALUE, -1);

  Write('Value: ', intValue);
  ReadLn;
end.

Na ekranie zostanie wyświetlona poniższa linijka:

Value: 2000600
A jeśli wystąpi jakikolwiek błąd podczas konwersji - funkcja zwróci przekazaną w parametrze ADefault wartość domyślną.

0

Gdy wpisuję #194 lub #160 to na miejscu spacji pojawia się znak zapytania.

for i:=1 to StringGrid1.RowCount-1 do
 begin
        d := StringGrid1.Cells[1,i];
        m := StringReplace(d, #194, '', [rfReplaceAll]);
        StringGrid1.Cells[1,i] := m;
 end;

A co do tego debuggera: _13th_Dragon:: Twój sposób ma na celu ręczne zmienianie wartości, odnalezienie kodu tej spacji czy jeszcze coś innego?
Jakieś zupełnie mi obce okienka pootwierałam, ale nie bardzo wiem co mam z tym dalej zrobić... ;d Jest tam przykładowy Rezultat '320 000' a poniżej możliwość wprowadzenia nowej wartości (?): 'New Value', screen:

b3a717b6e80fc.png

poprawienie znacznika i dodanie obrazka do załączników posta - @furious programming

Przy funkcji furiousa :

Wyskakuje mi komunikat, że typ jest nie taki :P unit1.pas(399,35) Error: Incompatible type for arg no. 3: Got "LongInt", expected "AnsiString", przy takim kodzie:

for i:=1 to StringGrid1.RowCount-1 do
  begin
       p := StringGrid1.Cells[1,i];              // p : string
       j := ConvertStringToInt(p, -1);       //  j : string
       StringGrid2.Cells[9,i] := j;
  end;
0

Gdy wpisuję #194 lub #160 to na miejscu spacji pojawia się znak zapytania.

No dobrze, ale po co to robisz? Przecież kod ASCII znaku spacji to 32, a nie ponad 100...

1

Ale z tego co widzę to masz: #194#160

m := StringReplace(d, #194#160, '', [rfReplaceAll]);
1

Wiem, próbowałam i nic... nie ugięta jest ta spacja ;/

Pomijając fakt iż to nie jest spacja, @madzieq - pokaż ostatnią wersję kodu z dodanym tym, co podał @kAzek, bo nie wiemy czy dobrze tego używasz; W teorii powinno działać, ale zawsze można naskrobać funkcję, która nie będzie usuwać niepożądanych znaków z łańcucha, a w zamian wyciągnie tylko znaki odpowiadające cyfrom, które zawsze są jednobajtowe;

Edit: Spóźniłem z odpowiedzią, ale miałem przeczucie, że źle tego używasz :]

2

z http://www.utf8-chartable.de/
U+00A0 | c2a0 | NO-BREAK SPACE i wszysko jasne. Wychodzi na to że @_13th_Dragon miał rację tylko trzeba było podstawić właściwe kody znaków.

2

Lekarstwem na późniejsze przygody z nieokreślonymi separatorami jest napisanie sobie funkcji, która usunie z ciągu wszystkie "niecyfrowe" znaki, przed właściwą konwersją; Poniżej masz przykład takiej funkcji:

function ConvertStringToInt(AValue: AnsiString; ADefault: Integer): Integer;
var
  intToken: Integer;
begin
  intToken := 1;

  while intToken <= Length(AValue) do
  begin
    if AValue[intToken] in ['0' .. '9'] then
      Inc(intToken)
    else
      Delete(AValue, intToken, 1);
  end;

  Result := StrToIntDef(AValue, ADefault);
end;

No i wywołanie na przykładowym ciągu, zawierającym wspomnianą sekwencję #194#160:

var
  SOME_VALUE: AnsiString = '429'#194#160'720'#194#160'm';
  intValue: Integer;
begin
  intValue := ConvertStringToInt(SOME_VALUE, -1);
  Write('Value: ', intValue);
  ReadLn;
end.

Wynik w konsoli:

Value: 429720
Bez problemu możesz zastosować powyższą funkcję ConvertStringToInt w swoim programie.

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