spiegel-keyman/common/windows/delphi/vcl/Keyman.System.RegExGroupHelperRSP19902.pas

81 lines
2.2 KiB
ObjectPascal

unit Keyman.System.RegExGroupHelperRSP19902;
interface
//
// Ref: https://quality.embarcadero.com/browse/RSP-19902
//
// TRegEx Groups return the wrong value when using supplementary plane (SMP)
// characters in an input string. The position is off by 1 for each SMP
// character prior to the match in the input string, it seems because the
// regex engine is (correctly) matching UTF-16 surrogate pairs as a single
// character, whereas the grouping code is treating them as two separate
// characters.
//
// This workaround resolves the problem. However if the problem is fixed in
// the library, then this workaround will fail. See the corresponding unit test
// to make sure that we pick up when this happens.
//
// Fixed in VER330 (Delphi 10.3 Rio, 20.0)
uses
System.Character,
System.Types,
System.SysUtils,
System.RegularExpressions;
type
TGroupHelperRSP19902 = record
private
{$IFDEF VER320}
FInput: string;
FSourceGroup: TGroup;
{$ENDIF}
FFixedIndex, FFixedLength: Integer;
FFixedValue: string;
public
constructor Create(SourceGroup: TGroup; const Input: string);
property FixedIndex: Integer read FFixedIndex;
property FixedLength: Integer read FFixedLength;
property FixedValue: string read FFixedValue;
end;
implementation
{ TGroupHelperRSP19902 }
constructor TGroupHelperRSP19902.Create(SourceGroup: TGroup; const Input: string);
{$IFDEF VER320}
var
i: Integer;
begin
FSourceGroup := SourceGroup;
FInput := Input;
FFixedIndex := 1; //Self.Index;
for i := 1 to SourceGroup.Index - 1 do
begin
if input[FFixedIndex].IsHighSurrogate and (FFixedIndex < input.Length) and input[FFixedIndex+1].IsLowSurrogate then
Inc(FFixedIndex);
Inc(FFixedIndex);
end;
FFixedLength := 0;
for i := 1 to SourceGroup.Length do
begin
if input[FFixedLength+FFixedIndex].IsHighSurrogate and (FFixedLength+FFixedIndex < input.Length) and input[FFixedLength+FFixedIndex+1].IsLowSurrogate then
Inc(FFixedLength);
Inc(FFixedLength);
end;
FFixedValue := Copy(input, FFixedIndex, FFixedLength);
{$ELSE}
begin
// This was fixed in VER320 so
FFixedIndex := SourceGroup.Index;
FFixedLength := SourceGroup.Length;
FFixedValue := SourceGroup.Value;
{$ENDIF}
end;
end.