【发布时间】:2011-04-13 14:00:55
【问题描述】:
我需要从字符串中删除所有非标准文本字符。我需要删除所有非 ascii 和控制字符(换行符/回车符除外)。
【问题讨论】:
标签: delphi parsing ascii delphi-2010 delphi-7
我需要从字符串中删除所有非标准文本字符。我需要删除所有非 ascii 和控制字符(换行符/回车符除外)。
【问题讨论】:
标签: delphi parsing ascii delphi-2010 delphi-7
这是 Cosmin 的一个变体,它只遍历字符串一次,但使用了一种高效的分配模式:
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;
【讨论】:
应该这样做:
// 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,你可以做类似的事情。
【讨论】:
如果您不需要就地执行此操作,而是生成字符串的副本,请尝试此代码
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]);
编辑:为 DEL ctrl char 添加了 #127。
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;
【讨论】:
CharInSet 函数而不是 Ch in ... 构造。
这是一个不通过逐个字符附加来构建字符串的版本,而是一次性分配整个字符串。它需要遍历字符串两次,一次计算“好”字符,一次有效复制这些字符,但这是值得的,因为它不会进行多次重新分配:
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;
【讨论】:
SetLength 并实现一个微小的优化,允许例程使用零或 1 个字符串分配来完成工作。
我的性能解决方案;
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写的
【讨论】:
我的 Result 字节数组版本:
界面
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;
【讨论】: