如何从字符串中删除重复的空格

3
我需要从一个字符串中删除重复的空格。 以下代码来自于互联网,工作得还不错,除了它会复制字符串的第一个字符。 也许有比这更快的方法。
function DeleteRepeatedSpaces(OldText: string): string;
var
  i: integer;
  s: string;
begin
   if length(OldText) > 0 then
    s := OldText[1]
  else
    s := '';

  for i := 1 to length(OldText) do
  begin
    if OldText[i] = ' ' then
    begin
      if not (OldText[i - 1] = ' ') then
        s := s + ' ';
    end
    else
    begin
      s := s + OldText[i];
    end;
  end;

  DelDoubleSpaces := s;
end;
4个回答

7

基于最简有限状态自动机(DFA)的函数。最小化内存重新分配。
State 表示连续空格数量。
J 表示删除的空格数。

  function DeleteRepeatedSpaces(const s: string): string;
  var
    i, j, State: Integer;
  begin
    SetLength(Result, Length(s));
    j := 0;
    State := 0;

    for i := 1 to Length(s) do begin

      if s[i] = ' ' then
        Inc(State)
      else
        State := 0;

      if State < 2 then
        Result[i - j] := s[i]
      else
        Inc(j);

    end;

    if j > 0 then
        SetLength(Result, Length(s) - j);
  end;

4

遍历字符串的所有成员,将字符移动到结果中,但跳过重复的空格。

function DeleteRepeatedSpaces(const OldText: string): string;
var
  i,j,hi: Integer;
begin
  SetLength(Result,Length(OldText));
  i := Low(OldText);
  j := i;
  hi := High(OldText);
  while (i <= hi) do begin
    Result[j] := OldText[i];
    Inc(j);
    if (OldText[i] = ' ') then begin
      repeat  //Skip additional spaces
        Inc(i);
      until (i > hi) or (OldText[i] <> ' ');
    end
    else
      Inc(i);
  end;
  SetLength(Result,j-Low(Result));  // Set correct length
end;

上面的代码非常快(比迄今为止的任何其他贡献都要快)。

下面是一个更加优化的例程:

function DeleteRepeatedSpaces(const OldText: string): string;
var
  pO,pR: PChar;
begin
  SetLength(Result,Length(OldText));
  pR := Pointer(Result);
  pO := Pointer(OldText);
  while (pO^ <> '') do begin
    pR^ := pO^;
    Inc(pR);
    if (pO^ <> ' ') then begin
      Inc(pO);
      Continue;
    end;
    repeat // Skip additional spaces
      Inc(pO);
    until (pO^ = '') or (pO^ <> ' ');
  end;
  SetLength(Result,pR-Pointer(Result));
end;

1
我想这个程序可能比你的“更优化的例程”更快不了。感谢。 - Tom Brunberg

3
以下方法不是非常高效,但可能比逐个处理字符串字符更加高效,因为它不需要为输出中的每个字符进行新字符串分配:
function RemoveDupSpaces(const Input : String) : String;
var
  P : Integer;
begin
  Result := Input;
  repeat
    P := Pos('  ', Result);  // that's two spaces
    if P > 0 then
      Delete(Result, P + 1, 1);
  until P = 0;
end;

-1
你可以使用类似这样的代码:
function DeleteRepeatedSpaces(const s: string):string;
var
  i:integer;
begin
  Result := '';
  for i := 1 to Length(S) do begin
    if not ((s[i]=' ') and (s[i-1]=' ')) then begin
      Result := Result + s[i];
    end;
  end;
end;

删除字符串中连续的两个或更多空格。

这个字符串(无空格):

The string have groups of spaces inside

返回这个:

The string have groups of spaces inside

这个字符串(内部带有空格组):

The   string  have       groups    of  spaces   inside

返回这个:
The string have groups of spaces inside

2
如果s以空格开头怎么办?s[i-1]有效吗? - Tom Brunberg
是的。for..begin从索引1开始。这个特殊情况已经测试过了。 - Germán Estévez -Neftalí-
为什么要踩我?我不明白。这段代码运行良好。我违反了什么规定吗? - Germán Estévez -Neftalí-
3
按预期,在进行范围检查时访问s[0]会引发范围检查错误。 s[0] 是长度字段的高位字,因此对于长度小于65536个字符的字符串为0,因此您的函数“大多数情况下”可正常工作。然而,这是错误的。 - Tom Brunberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接