type
tMap = array[ 0..255 ] of UInt8;
tFreq = array[ 0..127 ] of UInt8;
const
Mapping: array [ 0..255 ] of UInt8 =
(
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f,
$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f,
$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f,
$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$5b,$5c,$5d,$5e,$5f,
$60,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f,
$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$7b,$7c,$7d,$7e,$7f,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,
$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
);
procedure Histogram( Str: pUInt8; Count: UInt8; constref Map: tMap; var Freq: tFreq );
var
Flag: UInt8;
Part: UInt64;
begin
Flag := UInt8( Count<8 );
while( Flag=0 ) do
begin
Part := Unaligned( pUInt64( Str )^ );
Inc( Freq[ Map[ Part and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 8 ) and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 16 ) and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 24 ) and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 32 ) and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 40 ) and $ff ] ] );
Inc( Freq[ Map[ ( Part shr 48 ) and $ff ] ] );
Inc( Freq[ Map[ Part shr 56 ] ] );
Dec( Count, 8 );
Inc( Str, 8 );
Flag := Freq[ 0 ] + UInt8( Count<8 );
end;
Flag := UInt8( Count=0 );
while( Flag=0 ) do
begin
Dec( Count );
Inc( Freq[ Map[ Str^ ] ] );
Inc( Str );
Flag := Freq[ 0 ] + UInt8( Count=0 );
end;
end;
// ATTN: the following may fail, if Length( S )>255
function IsAnagramMM(const S1, S2: string; IgnoreSpaces: boolean = True; ExceptionOnError: boolean = False): boolean;
var
Freq1: tFreq;
Freq2: tFreq;
begin
Freq1 := Default( tFreq );
Histogram( pUInt8( @S1[ 1 ] ), Length( S1 ), Mapping, Freq1 );
if( Freq1[ 0 ]<>0 ) then
if ExceptionOnError then
raise ERangeError.Create( 'IsAnagram: illegal character in S1' )
else
Exit( FALSE );
Freq2 := Default( tFreq );
Histogram( pUInt8( @S2[ 1 ] ), Length( S2 ), Mapping, Freq2 );
if( Freq2[ 0 ]<>0 ) then
if ExceptionOnError then
raise ERangeError.Create( 'IsAnagram: illegal character in S2' )
else
Exit( FALSE );
if( ( IgnoreSpaces=FALSE ) and ( Freq1[ $20 ]<>Freq2[ $20 ] ) ) then Exit( FALSE );
Freq1[ $20 ] := 0;
Freq2[ $20 ] := 0;
Result := CompareDWord( Freq1[ $20 ], Freq2[ $20 ], ( SizeOf( tFreq )-$20 ) div 4 )=0;
end;