Ответ 1
Я могу воспроизвести ошибку в Delphi XE4. Я получаю правильное поведение в Delphi XE5.
Ошибка была в TPerlRegEx.ComputeReplacement
. Код, который я внес в Embarcadero для включения в Delphi XE3, использовал UTF8String
. С Delphi XE4 Embarcadero удалил UTF8String
из блока RegularExpressionsCore
и заменил его на TBytes
. Разработчик, который сделал это изменение, похоже, пропустил ключевое различие между строками и динамическими массивами в Delphi. Строки используют механизм копирования на запись, а динамические массивы - нет.
Итак, в моем исходном коде TPerlRegEx.ComputeReplacement
может сделать S := FReplacement
, а затем изменить временную переменную S
, чтобы заменить обратные ссылки, не затрагивая поле FReplacement
, потому что оба были строками. В модифицированном коде S := FReplacement
делает S
указывать на тот же массив, что и FReplacement
, и когда обратные ссылки в S
заменяются, также изменяется t28. Следовательно, первая замена выполнена правильно, а последующие замены ошибочны, потому что FReplacement
был искалечен.
В Delphi XE5 это было исправлено заменой S := FReplacement
на это, чтобы создать надлежащую временную копию:
SetLength(S, Length(FReplacement));
Move(FReplacement[0], S[0], Length(FReplacement));
Когда был выпущен Delphi 2009, было много разговоров с Embarcadero о том, что нельзя использовать типы строк для представления последовательностей байтов. Кажется, теперь они делают противоположную ошибку в использовании TBytes для представления строк.
Решение этой проблемы, которую я ранее рекомендовал Embarcadero, заключается в том, чтобы переключиться на новые функции pcre16, которые используют UTF16LE так же, как строки Delphi. Эти функции не существовали, когда Delphi XE был выпущен, но теперь они работают, и они должны использоваться.