Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Как исправить ошибку доступа при очистке строки от невидимых символов в Delphi 12.2 Athens

Delphi , Синтаксис , Текст и Строки

 

При работе со строками в Delphi разработчики часто сталкиваются с необходимостью очистки текста от нежелательных символов, особенно при обработке данных из внешних источников. В этой статье мы разберём распространённую ошибку доступа (access violation) при фильтрации строк и предложим несколько рабочих решений.

Проблема в исходном коде

Исходная функция для очистки строки выглядит следующим образом:

function MyCleanText(const AText: string): string;
var
  I, Len, Count: Integer;
  C: Char;
  Buf: TArray<Char>;
begin
  Len := Length(AText);
  if Len = 0 then
    Exit('');

  SetLength(Buf, Len);
  Count := 0;

  for I := 1 to Len do
  begin
    C := AText[I];

    // 1) Сохраняем табуляции (#9), переводы строк (#10) и возвраты каретки (#13)
    if (C = #9) or (C = #10) or (C = #13) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end
    // 2) Преобразуем другие пробельные символы в обычный пробел
    else if C.IsWhiteSpace then
    begin
      Buf[Count] := ' ';
      Inc(Count);
    end
    // 3) Сохраняем ASCII/расширенный ASCII (#32..#255)
    else if (Ord(C) >= 32) and (Ord(C) <= 255) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end;
    // 4) Остальные символы пропускаем
  end;

  SetLength(Buf, Count);
  Result := String(Buf);
end;

Основная проблема в этом коде - некорректное преобразование массива символов TArray<Char> в строку через прямое приведение типов String(Buf). Это вызывает ошибку доступа, так как Delphi неправильно интерпретирует структуру данных.

Решение 1: Использование PChar с нуль-терминатором

function MyCleanText(const AText: string): string;
var
  I, Len, Count: Integer;
  C: Char;
  Buf: TArray<Char>;
begin
  Len := Length(AText);
  if Len = 0 then
    Exit('');

  SetLength(Buf, Len + 1); // +1 для нуль-терминатора
  Count := 0;

  for I := 1 to Len do
  begin
    C := AText[I];
    if (C = #9) or (C = #10) or (C = #13) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end
    else if C.IsWhiteSpace then
    begin
      Buf[Count] := ' ';
      Inc(Count);
    end
    else if (Ord(C) >= 32) and (Ord(C) <= 255) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end;
  end;

  Buf[Count] := #0; // Добавляем нуль-терминатор
  Result := PChar(Buf);
end;

Решение 2: Использование SetString

Более элегантное решение с использованием SetString:

function MyCleanText(const AText: string): string;
var
  I, Len, Count: Integer;
  C: Char;
  Buf: TArray<Char>;
begin
  Len := Length(AText);
  if Len = 0 then
    Exit('');

  SetLength(Buf, Len);
  Count := 0;

  for I := 1 to Len do
  begin
    C := AText[I];
    if (C = #9) or (C = #10) or (C = #13) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end
    else if C.IsWhiteSpace then
    begin
      Buf[Count] := ' ';
      Inc(Count);
    end
    else if (Ord(C) >= 32) and (Ord(C) <= 255) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end;
  end;

  SetString(Result, PChar(Buf), Count);
end;

Решение 3: Модификация строки напрямую

Альтернативный подход без использования промежуточного массива:

function MyCleanText(const AText: string): string;
var
  I, Len: Integer;
  C: Char;
begin
  Len := Length(AText);
  if Len = 0 then
    Exit('');

  Result := AText;
  I := 1;

  while I <= Len do
  begin
    C := AText[I];

    if (C = #9) or (C = #10) or (C = #13) or
       ((Ord(C) >= 32) and (Ord(C) <= 255)) then
    begin
      Inc(I);
    end
    else if C.IsWhiteSpace then
    begin
      Result[I] := ' ';
      Inc(I);
    end
    else
    begin
      Delete(Result, I, 1);
      Dec(Len);
    end;
  end;
end;

Улучшенная версия с поддержкой Unicode

Если вам нужно сохранять Unicode-символы (коды > 255), модифицируйте условие:

function MyCleanText(const AText: string): string;
var
  I, Len, Count: Integer;
  C: Char;
  Buf: TArray<Char>;
begin
  Len := Length(AText);
  if Len = 0 then
    Exit('');

  SetLength(Buf, Len);
  Count := 0;

  for I := 1 to Len do
  begin
    C := AText[I];

    // Сохраняем управляющие символы форматирования
    if (C = #9) or (C = #10) or (C = #13) then
    begin
      Buf[Count] := C;
      Inc(Count);
    end
    // Преобразуем другие пробельные символы
    else if C.IsWhiteSpace then
    begin
      Buf[Count] := ' ';
      Inc(Count);
    end
    // Сохраняем все видимые символы (включая Unicode)
    else if not C.IsControl then
    begin
      Buf[Count] := C;
      Inc(Count);
    end;
  end;

  SetString(Result, PChar(Buf), Count);
end;

Заключение

Ошибка доступа в исходной функции возникала из-за неправильного преобразования массива символов в строку. Мы рассмотрели три рабочих решения:

  1. Использование PChar с нуль-терминатором
  2. Применение функции SetString
  3. Прямая модификация строки

Для большинства случаев рекомендуется использовать второй вариант с SetString, как наиболее надежный и читаемый. Если же вам важна производительность при обработке очень длинных строк, стоит рассмотреть третий вариант.

Дополнительно мы улучшили функцию, добавив корректную обработку Unicode-символов через метод IsControl, что делает решение более универсальным.

Создано по материалам из источника по ссылке.

В статье рассматривается проблема ошибки доступа при очистке строк в Delphi, предлагаются различные решения, включая использование PChar с нуль-терминатором, функции SetString и прямую модификацию строки, а также улучшенная версия с поддержкой Unicode.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




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


:: Главная :: Текст и Строки ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-01 10:30:39/0.003864049911499/0