mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 16:35:33 +00:00
81 lines
2.2 KiB
ObjectPascal
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.
|