Как убрать пространство вокруг персонажа? - PullRequest
8 голосов
/ 09 ноября 2011

Скажите, у меня есть следующая строка:

s := 'This , is,       the Delphi  ,    World!';

Я хотел бы следующий вывод:

Result := 'This,is,the Delphi,World!';

В основном мне нужна процедура, которая удаляет ALL вхождений пробелов ONLY , если они появляются до или после запятой (являющейся моим разделителем), оставляя неповрежденные пробелы между другими словами.

Любая помощь очень ценится.

Что вы думаете об этом решении?

function RemoveSpacesAroundDelimiter(var aString: string; aDelimiter:
    string): string;
begin
  while AnsiContainsText(aString, aDelimiter + ' ') do
    begin
    aString := StringReplace(aString, ', ', aDelimiter, [rfReplaceAll, rfIgnoreCase]);
    end;

  while AnsiContainsText(aString, ' ' + aDelimiter) do
    begin
    aString := StringReplace(aString, ' ' + aDelimiter, aDelimiter, [rfReplaceAll, rfIgnoreCase]);
    end;

  Result := aString;
end;

спасибо

Fabio

Ответы [ 10 ]

9 голосов
/ 09 ноября 2011

Похоже на задачу для TStringList.

function UltraTrim(Value: string): string;
var
  sl: TStringList;
  i: Integer;
begin
  sl := TStringList.Create;
  try
    // Prevent the stringlist from using spaces as delimiters too.
    sl.StrictDelimiter := True;

    // Set the comma separated text.
    sl.CommaText := Value;

    // Trim each item.
    for i := 0 to sl.Count -1 do
      sl[i] := Trim(sl[i]);

    // Concat back to comma separated string.
    Result := sl.CommaText;
  finally
    sl.Free;
  end;

end;
4 голосов
/ 09 ноября 2011

Быстрая версия может быть:

function RemoveSpacesAroundDelimiter(const aString: string; aDelimiter: char = ','): string;
var S, D, D2: PChar;
begin
  SetLength(result,length(aString));
  if aString<>'' then
  begin
    S := pointer(aString);
    D := pointer(result);
    while S^<>#0 do
    begin
      if S^=' ' then
      begin
        D2 := D;
        repeat
          inc(S);
          D^ := ' ';
          inc(D);
        until S^<>' ';
        if S^=#0 then
          break;
        if S^=aDelimiter then
          D := D2; // trim spaces before comma
      end;
      D^ := S^;
      if (S[0]=aDelimiter) and (S[1]=' ') then
        repeat inc(S) until S^<>' ' else // trim spaces after comma
        inc(S);
      inc(D);
    end;
    SetLength(result,D-pointer(result));
  end;
end;

Некоторые тестовые коды:

  assert(RemoveSpacesAroundDelimiter('one two,three')='one two,three');
  assert(RemoveSpacesAroundDelimiter('one two , three')='one two,three');
  assert(RemoveSpacesAroundDelimiter('one,two,three')='one,two,three');
  assert(RemoveSpacesAroundDelimiter('one   ,   two,  three')='one,two,three');
3 голосов
/ 09 ноября 2011

Если вы используете Delphi XE или выше, вы можете сделать это тривиально в одной строке кода, используя регулярное выражение.

program regex;

{$APPTYPE CONSOLE}

uses
  RegularExpressions;

const
  Input = 'This , is,       the Delphi  ,    World!';

begin
  Writeln(TRegEx.Replace(Input, ' *, *', ','));
  Readln;
end.

Естественно, это не самый быстрый вариант предлагаемых решений, но, возможно, это не имеет значения для вас.

3 голосов
/ 09 ноября 2011

Скопируйте символы один за другим в буфер назначения, но найдите пробелы и разделители и запомните последнее местоположение, в которое вы скопировали непробельный символ.Если вы видите пробел и последний не пробел, который вы скопировали, был разделителем, пропустите пробел.Если это пробел и последний скопированный вами символ не был разделителем, скопируйте его в место назначения, но помните последний не пробел, который вы добавили.Таким образом, если вы увидите разделитель позже, вы можете вернуться и перезаписать его.

function RemoveSpacesAroundDelimiter(const AString: string; ADelimiter: Char): string;
var
  c: Char;
  dest: Integer;
  LastNonSpace: Integer;
  HaveDelimiter: Boolean;
begin
  Assert(ADelimiter <> ' ');
  SetLength(Result, Length(AString));
  dest := 1;
  LastNonSpace := 0;
  HaveDelimiter := False;
  for c in AString do begin
    if (c = ' ') and HaveDelimiter then
      continue; // Skip this character

    if c = ADelimiter then begin
      dest := LastNonSpace + 1;
      HaveDelimiter := True;
    end else
      HaveDelimiter := False;
    Result[dest] := c;
    if c <> ' ' then
      LastNonSpace := dest;
    Inc(dest);
  end;
  SetLength(Result, dest - 1);
end;
1 голос
/ 09 ноября 2011

Самый простой и легкий способ - использовать регулярные выражения. Последнее, что вам нужно, это огромный сложный блок кода для решения такой простой задачи. К сожалению, у меня сейчас нет Delphi, я не могу протестировать этот код, но если он не совсем такой, он очень близко:

s := 'This , is,       the Delphi  ,    World!';
RegEx := TRegEx.Create('[ ]*,[ ]*');
CleanStr := RegEx.Replace(s, ',');
1 голос
/ 09 ноября 2011

Вы можете использовать регулярные выражения. Вы хотите найти разделитель, предшествующий или сопровождаемый любым количеством пробелов, и заменить его одной копией разделителя.

function RemoveSpacesAroundDelimiter(const AString: string; const ADelimiter: string): string;
var
  re: TPerlRexEx;
begin
  re := TPerlRegEx.Create;
  try
    re.RegEx := '\s*' + TPerlRegEx.EscapeRegExChars(ADelimiter) + '\s*';
    re.Subject := AString;
    re.Replacement := TPerlRegEx.EscapeRegExChars(ADelimiter);
    re.ReplaceAll;
    Result := re.Subject;
  finally
    re.Free;
  end;
end;

Более новые версии Delphi могут использовать встроенный RegularExpressionCore модуль. В старых версиях может использоваться эквивалентный блок PerlRegEx от Яна Гойваэрта .

Мик ранее отправил ответ , демонстрирующий это, но он удалил его, потому что он ошибся в регулярном выражении (удалив все пробелы вместо только тех, которые примыкают разделитель).

0 голосов
/ 03 июня 2013

с этой функцией:

function MBTrim(iStr :string):string;
const CTc= 3{Conditions Count};
      CT :array[0..(CTc-1),0..1]of string= ( (' ,', ','), (', ', ','), ('  ', ' ') );
var   i  :Integer;
begin
  for i := 0 to CTc-1 do while Pos(CT[i,0], iStr) > 0 do
    iStr:= StringReplace(iStr, CT[i,0], CT[i,1], [rfReplaceAll, rfIgnoreCase]);
  Result:= Trim(iStr);
end;

Вы можете просто добавить другие условия.

например, я добавляю (' ', ' ') для преобразования пробела между словами вроде:

'This , is,       the       Delphi  ,    World!'
0 голосов
/ 01 июня 2013

Используя библиотеку кодов джедаев, ответ @GolezTrol можно переформулировать, используя однострочник.

function UltraTrim(Value: string): string;
begin
  Result := JclStringList.Split(Value, ',').Trim.Join(',')
end;
0 голосов
/ 09 ноября 2011

Я думал, что это стоит добавить, потому что он будет работать с ранними версиями Delphi, чего нет в решении для списка строк (которое мне понравилось).

Я полагаю, это довольно быстро и довольно просто для чтения и понимания.

function TForm1.UltraTrim(const InString : String; Delim : Char) : String;
var
  Buf : String;
  i : Integer;
  Token : String;
begin
  Result := '';
  if Trim(InString) <> '' then begin
    i := 1;
    Buf := StringReplace(InString, Delim, #0, [rfReplaceAll]) + #0;
    while i < Length(Buf) do begin
      Token := StrPas(@Buf[i]);
      i := i + Length(Token) + 1;
      Result := Result + Delim + Trim(Token);
    end;
    Result := Copy(Result,2,Length(Result));
  end;
end;
0 голосов
/ 09 ноября 2011

Изменено, еще раз.

  while (pos(', ',s)>0) or (pos(' ,',s)>0) do   begin
    s := StringReplace(s, ', ', ',', [rfReplaceAll]);
    s := StringReplace(s, ' ,', ',', [rfReplaceAll]);   end;

ОК для всех версий Delphi.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...