Skip to content

Commit 023e8a2

Browse files
committed
Added compatibility normalization to UString. Updated to version 0.9.1.
1 parent c65ba79 commit 023e8a2

10 files changed

Lines changed: 317 additions & 165 deletions

File tree

UnicodeHelper.Tests/TestData/NormalizationTestDataSet.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88

99
namespace UnicodeHelper.TestData
1010
{
11-
public sealed record NormalizationTestData(UString Source, UString NfcResult, UString NfdResult, string Description)
11+
public sealed record NormalizationTestData(UString Source,
12+
UString NfcResult, UString NfdResult, UString NfkcResult, UString NfkdResult,
13+
string Description)
1214
{
1315
public override string ToString()
1416
{
1517
return Description;
1618
}
1719
}
1820

19-
/// <summary>
20-
///
21-
/// </summary>
2221
/// <remarks>Test data taken from https://www.unicode.org/Public/UCD/latest/ucd/NormalizationTest.txt</remarks>
2322
internal static class NormalizationTestDataSet
2423
{
@@ -55,6 +54,8 @@ static NormalizationTestDataSet()
5554
testCases.Add(new NormalizationTestData(CreateUStringFromCodepoints(line.Source),
5655
CreateUStringFromCodepoints(line.NfcResult),
5756
CreateUStringFromCodepoints(line.NfdResult),
57+
CreateUStringFromCodepoints(line.NfkcResult),
58+
CreateUStringFromCodepoints(line.NfkdResult),
5859
string.Join("", line.Comments).TrimStart(' ', '#')));
5960
}
6061
}

UnicodeHelper.Tests/UStringTests.cs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,8 @@ public void Normalization_FormC()
738738
foreach (NormalizationTestData testData in NormalizationTestDataSet.TestCases)
739739
{
740740
UString result = testData.Source.Normalize(NormalizationForm.FormC);
741-
Assert.AreEqual(testData.NfcResult, result, testData.Description);
741+
Assert.AreEqual(testData.NfcResult, result,
742+
ErrorString(testData.NfcResult, result, testData.Description));
742743
}
743744
}
744745

@@ -748,7 +749,30 @@ public void Normalization_FormD()
748749
foreach (NormalizationTestData testData in NormalizationTestDataSet.TestCases)
749750
{
750751
UString result = testData.Source.Normalize(NormalizationForm.FormD);
751-
Assert.AreEqual(testData.NfdResult, result, testData.Description);
752+
Assert.AreEqual(testData.NfdResult, result,
753+
ErrorString(testData.NfdResult, result, testData.Description));
754+
}
755+
}
756+
757+
[TestMethod]
758+
public void Normalization_FormKD()
759+
{
760+
foreach (NormalizationTestData testData in NormalizationTestDataSet.TestCases)
761+
{
762+
UString result = testData.Source.Normalize(NormalizationForm.FormKD);
763+
Assert.AreEqual(testData.NfkdResult, result,
764+
ErrorString(testData.NfkdResult, result, testData.Description));
765+
}
766+
}
767+
768+
[TestMethod]
769+
public void Normalization_FormKC()
770+
{
771+
foreach (NormalizationTestData testData in NormalizationTestDataSet.TestCases)
772+
{
773+
UString result = testData.Source.Normalize(NormalizationForm.FormKC);
774+
Assert.AreEqual(testData.NfkcResult, result,
775+
ErrorString(testData.NfkcResult, result, testData.Description));
752776
}
753777
}
754778
#endregion
@@ -764,6 +788,16 @@ private static UString CreateTestSubstring(string? str)
764788
UString us = new(pre + str + suff);
765789
return us.SubString(pre.Length, us.Length - pre.Length - suff.Length);
766790
}
791+
792+
private static string ErrorString(UString expected, UString result, string description)
793+
{
794+
return $"\nExp: {UStrToCodepoints(expected)}\nGot: {UStrToCodepoints(result)}\nFor:{description}";
795+
}
796+
797+
private static string UStrToCodepoints(UString ustr)
798+
{
799+
return string.Join(" ", ustr.Select(uc => uc.ToHexString()));
800+
}
767801
#endregion
768802
}
769803
}

UnicodeHelper/Internal/CompositionExclusions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66

77
namespace UnicodeHelper.Internal
88
{
9-
/// <summary>
10-
///
11-
/// </summary>
129
/// <remarks>This class represents the data in the Unicode specification
1310
/// <see href="https://www.unicode.org/reports/tr44/#CompositionExclusions.txt">CompositionExclusions.txt</see></remarks>
11+
/// <remarks>This class is designed to be used and thrown away since the data is only needed during the creation
12+
/// of the composition mappings.</remarks>
1413
internal sealed class CompositionExclusions
1514
{
1615
#region Data fields

UnicodeHelper/Internal/HelperUtils.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.CompilerServices;
34

45
namespace UnicodeHelper.Internal
56
{
@@ -39,5 +40,37 @@ public static TextDirection DetermineDirection(IEnumerable<UCodepoint> codepoint
3940

4041
return TextDirection.Undefined;
4142
}
43+
44+
/// <summary>
45+
/// Efficiently converts a bool to an int (0 or 1).
46+
/// </summary>
47+
/// <remarks>Taken from https://stackoverflow.com/a/66993553 </remarks>
48+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
49+
public static unsafe int BoolToInt(bool b)
50+
{
51+
return *(byte*)&b;
52+
}
53+
54+
/// <summary>
55+
/// Sorts the specified decomposed character array in Unicode canonical order (based on combining class).
56+
/// </summary>
57+
public static void SortCanonical(UCodepoint[] decomposedChar, int count)
58+
{
59+
for (int i = 1; i < count; i++)
60+
{
61+
byte ucClass = UnicodeData.GetCombiningClass(decomposedChar[i]);
62+
if (ucClass == 0)
63+
continue;
64+
65+
byte ucClassPrev = UnicodeData.GetCombiningClass(decomposedChar[i - 1]);
66+
if (ucClassPrev <= ucClass)
67+
continue;
68+
69+
// Swap items
70+
(decomposedChar[i], decomposedChar[i - 1]) = (decomposedChar[i - 1], decomposedChar[i]);
71+
if (i > 1)
72+
i -= 2; // Re-evaluate previous items
73+
}
74+
}
4275
}
4376
}

0 commit comments

Comments
 (0)