delphi-удаляет все нестандартные текстовые символы из строки
Мне нужно удалить все нестандартные текстовые символы из строки. Мне нужно удалить все не ascii и управляющие символы (кроме строк / возвратов каретки).
6 ответов:
Что-то вроде этого должно сделать:
// For those who need a disclaimer: // This code is meant as a sample to show you how the basic check for non-ASCII characters goes // It will give low performance with long strings that are called often. // Use a TStringBuilder, or SetLength & Integer loop index to optimize. // If you need really optimized code, pass this on to the FastCode people. function StripNonAsciiExceptCRLF(const Value: AnsiString): AnsiString; var AnsiCh: AnsiChar; begin for AnsiCh in Value do if (AnsiCh >= #32) and (AnsiCh <= #127) and (AnsiCh <> #13) and (AnsiCh <> #10) then Result := Result + AnsiCh; end;
Для
UnicodeString
Вы можете сделать нечто подобное.
А вот вариант Космина, который ходит по строке только один раз, но использует эффективный шаблон распределения:
function StrippedOfNonAscii(const s: string): string; var i, Count: Integer; begin SetLength(Result, Length(s)); Count := 0; for i := 1 to Length(s) do begin if ((s[i] >= #32) and (s[i] <= #127)) or (s[i] in [#10, #13]) then begin inc(Count); Result[Count] := s[i]; end; end; SetLength(Result, Count); end;
Если вам не нужно делать это на месте, но создать копию строки, попробуйте этот код
type CharSet=Set of Char; function StripCharsInSet(s:string; c:CharSet):string; var i:Integer; begin result:=''; for i:=1 to Length(s) do if not (s[i] in c) then result:=result+s[i]; end;
И использовать его вот так
s := StripCharsInSet(s,[#0..#9,#11,#12,#14..#31,#127]);
EDIT : добавлен #127 для DEL ctrl char.
EDIT2 : это более быстрая версия, Спасибо ldsandon
function StripCharsInSet(s:string; c:CharSet):string; var i,j:Integer; begin SetLength(result,Length(s)); j:=0; for i:=1 to Length(s) do if not (s[i] in c) then begin inc(j); result[j]:=s[i]; end; SetLength(result,j); end;
Вот версия, которая не строит строку путем добавления char-by-char, но выделяет всю строку за один раз. Для этого требуется дважды пройти по строке, один раз, чтобы посчитать "хороший" символ, один раз, чтобы эффективно скопировать эти символы, но это стоит того, потому что он не делает многократных перераспределений:
function StripNonAscii(s:string):string; var Count, i:Integer; begin Count := 0; for i:=1 to Length(s) do if ((s[i] >= #32) and (s[i] <= #127)) or (s[i] in [#10, #13]) then Inc(Count); if Count = Length(s) then Result := s // No characters need to be removed, return the original string (no mem allocation!) else begin SetLength(Result, Count); Count := 1; for i:=1 to Length(s) do if ((s[i] >= #32) and (s[i] <= #127)) or (s[i] in [#10, #13]) then begin Result[Count] := s[i]; Inc(Count); end; end; end;
Мое решение по производительности;
function StripNonAnsiChars(const AStr: String; const AIgnoreChars: TSysCharSet): string; var lBuilder: TStringBuilder; I: Integer; begin lBuilder := TStringBuilder.Create; try for I := 1 to AStr.Length do if CharInSet(AStr[I], [#32..#127] + AIgnoreChars) then lBuilder.Append(AStr[I]); Result := lBuilder.ToString; finally FreeAndNil(lBuilder); end; end;
Я написал delphi xe7
Моя версия с результирующим массивом байт:
Интерфейс
type TSBox = array of byte;
И функция:
function StripNonAscii(buf: array of byte): TSBox; var temp: TSBox; countr, countr2: integer; const validchars : TSysCharSet = [#32..#127]; begin if Length(buf) = 0 then exit; countr2:= 0; SetLength(temp, Length(buf)); //setze temp auf länge buff for countr := 0 to Length(buf) do if CharInSet(chr(buf[countr]), validchars) then begin temp[countr2] := buf[countr]; inc(countr2); //count valid chars end; SetLength(temp, countr2); Result := temp; end;