delphi - удаляет все нестандартные текстовые символы из строки - PullRequest
12 голосов
/ 13 апреля 2011

Мне нужно вычеркнуть все нестандартные символы текста из строки. Мне нужно удалить все не ascii и управляющие символы (кроме перевода строки / возврата каретки).

Ответы [ 6 ]

20 голосов
/ 13 апреля 2011

А вот вариант Cosmin's, который обходит строку только один раз, но использует эффективный шаблон распределения:

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;
13 голосов
/ 13 апреля 2011

Примерно так должно поступить:

// 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 вы можете сделать что-то подобное.

5 голосов
/ 13 апреля 2011

если вам не нужно делать это на месте, а генерировать копию строки, попробуйте этот код

 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]);

РЕДАКТИРОВАНИЕ : добавлено # 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;  
3 голосов
/ 13 апреля 2011

Вот версия, которая не строит строку путем добавления 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;
0 голосов
/ 03 сентября 2017

моя версия с массивом результатов байта:

интерфейс

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;
0 голосов
/ 06 апреля 2015

мое решение по производительности;

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

...