diff --git a/UnicodeCharacterInspector/App.xaml b/UnicodeCharacterInspector/App.xaml index 44d587c..281b4f0 100644 --- a/UnicodeCharacterInspector/App.xaml +++ b/UnicodeCharacterInspector/App.xaml @@ -7,7 +7,9 @@ - + + + diff --git a/UnicodeCharacterInspector/CharacterInfoViewModel.cs b/UnicodeCharacterInspector/CharacterInfoViewModel.cs index 0f9d631..6b92310 100644 --- a/UnicodeCharacterInspector/CharacterInfoViewModel.cs +++ b/UnicodeCharacterInspector/CharacterInfoViewModel.cs @@ -67,6 +67,7 @@ namespace UnicodeCharacterInspector NotifyPropertyChanged(nameof(NumericValue)); NotifyPropertyChanged(nameof(ContributoryProperties)); NotifyPropertyChanged(nameof(CoreProperties)); + NotifyPropertyChanged(nameof(RadicalStrokeCounts)); NotifyPropertyChanged(nameof(CrossReferences)); NotifyPropertyChanged(nameof(MandarinReading)); NotifyPropertyChanged(nameof(CantoneseReading)); @@ -173,6 +174,11 @@ namespace UnicodeCharacterInspector get { return character != null ? characterInfo.CoreProperties : null as CoreProperties?; } } + public UnicodeRadicalStrokeCountCollection RadicalStrokeCounts + { + get { return character != null ? characterInfo.UnicodeRadicalStrokeCounts : new UnicodeRadicalStrokeCountCollection(); } + } + public UnicodeCrossReferenceCollection CrossReferences { get { return character != null ? characterInfo.CrossRerefences : new UnicodeCrossReferenceCollection(); } diff --git a/UnicodeCharacterInspector/MainWindow.xaml b/UnicodeCharacterInspector/MainWindow.xaml index 80cfb98..601871f 100644 --- a/UnicodeCharacterInspector/MainWindow.xaml +++ b/UnicodeCharacterInspector/MainWindow.xaml @@ -87,6 +87,7 @@ + @@ -105,52 +106,64 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - • “” U+ + Radical (), strokes + + + + + + + “” U+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + “” U+ diff --git a/UnicodeCharacterInspector/RadicalStrokeCountToCharConverter.cs b/UnicodeCharacterInspector/RadicalStrokeCountToCharConverter.cs new file mode 100644 index 0000000..9aee325 --- /dev/null +++ b/UnicodeCharacterInspector/RadicalStrokeCountToCharConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Globalization; +using System.Unicode; +using System.Windows.Data; + +namespace UnicodeCharacterInspector +{ + internal sealed class RadicalStrokeCountToCharConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) return null; + + var radicalStrokeCount = (UnicodeRadicalStrokeCount)value; + var radical = UnicodeInfo.GetCjkRadicalInfo(radicalStrokeCount.Radical); + + return radicalStrokeCount.IsSimplified ? radical.TraditionalRadicalCodePoint : radical.SimplifiedRadicalCodePoint; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/UnicodeCharacterInspector/StringToUtf32Converter.cs b/UnicodeCharacterInspector/StringToUtf32Converter.cs new file mode 100644 index 0000000..d6c6b36 --- /dev/null +++ b/UnicodeCharacterInspector/StringToUtf32Converter.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Data; + +namespace UnicodeCharacterInspector +{ + internal class StringToUtf32Converter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + string text = value as string; + + if (!string.IsNullOrEmpty(text)) return char.ConvertToUtf32(text, 0); + else return null; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +} diff --git a/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj b/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj index e622ee6..7dc17f9 100644 --- a/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj +++ b/UnicodeCharacterInspector/UnicodeCharacterInspector.csproj @@ -77,6 +77,8 @@ Placeholder.cs + + diff --git a/UnicodeInformation.Builder/Program.cs b/UnicodeInformation.Builder/Program.cs index 68af15e..31e0359 100644 --- a/UnicodeInformation.Builder/Program.cs +++ b/UnicodeInformation.Builder/Program.cs @@ -21,6 +21,7 @@ namespace System.Unicode.Builder "UnicodeData.txt", "PropList.txt", "DerivedCoreProperties.txt", + "CJKRadicals.txt", //"Jamo.txt", // Not used right now, as the hangul syllable algorithm implementation takes care of this. "NameAliases.txt", "NamesList.txt", diff --git a/UnicodeInformation.Builder/UnicodeCharacterDataBuilder.cs b/UnicodeInformation.Builder/UnicodeCharacterDataBuilder.cs index ac33310..d818f73 100644 --- a/UnicodeInformation.Builder/UnicodeCharacterDataBuilder.cs +++ b/UnicodeInformation.Builder/UnicodeCharacterDataBuilder.cs @@ -37,7 +37,7 @@ namespace System.Unicode.Builder set { name = value; } } - public ICollection NameAliases { get { return nameAliases; } } + public IList NameAliases { get { return nameAliases; } } public UnicodeCategory Category { @@ -124,7 +124,7 @@ namespace System.Unicode.Builder set { coreProperties = value; } } - public ICollection CrossRerefences { get { return crossRerefences; } } + public IList CrossRerefences { get { return crossRerefences; } } public UnicodeCharacterDataBuilder(int codePoint) : this(new UnicodeCharacterRange(codePoint)) diff --git a/UnicodeInformation.Builder/UnicodeDataProcessor.cs b/UnicodeInformation.Builder/UnicodeDataProcessor.cs index bd1abc3..fb8ccd7 100644 --- a/UnicodeInformation.Builder/UnicodeDataProcessor.cs +++ b/UnicodeInformation.Builder/UnicodeDataProcessor.cs @@ -13,6 +13,7 @@ namespace System.Unicode.Builder public const string UnicodeDataFileName = "UnicodeData.txt"; public const string PropListFileName = "PropList.txt"; public const string DerivedCorePropertiesFileName = "DerivedCoreProperties.txt"; + public const string CjkRadicalsFileName = "CJKRadicals.txt"; public const string NameAliasesFileName = "NameAliases.txt"; public const string NamesListFileName = "NamesList.txt"; public const string BlocksFileName = "Blocks.txt"; @@ -40,6 +41,7 @@ namespace System.Unicode.Builder await ProcessUnicodeDataFile(ucdSource, builder).ConfigureAwait(false); await ProcessPropListFile(ucdSource, builder).ConfigureAwait(false); await ProcessDerivedCorePropertiesFile(ucdSource, builder).ConfigureAwait(false); + await ProcessCjkRadicalsFile(ucdSource, builder).ConfigureAwait(false); await ProcessNameAliasesFile(ucdSource, builder).ConfigureAwait(false); await ProcessNamesListFile(ucdSource, builder).ConfigureAwait(false); await ProcessBlocksFile(ucdSource, builder).ConfigureAwait(false); @@ -202,6 +204,53 @@ namespace System.Unicode.Builder } } + private static async Task ProcessCjkRadicalsFile(IDataSource ucdSource, UnicodeInfoBuilder builder) + { + using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(CjkRadicalsFileName).ConfigureAwait(false), ';')) + { + int lastReadRadical = 0; + + while (reader.MoveToNextLine()) + { + string radicalIndexText = reader.ReadField(); + bool isSimplified = radicalIndexText[radicalIndexText.Length - 1] == '\''; + int radicalIndex = int.Parse(isSimplified ? radicalIndexText.Substring(0, radicalIndexText.Length - 1) : radicalIndexText); + + if (isSimplified ? radicalIndex != lastReadRadical : lastReadRadical + 1 != (lastReadRadical = radicalIndex)) + throw new InvalidDataException("Did not expect radical number " + radicalIndexText + "."); + + char radicalCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber)); + char characterCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber)); + + if (!isSimplified && (radicalCodePoint & 0x8000) != 0) + throw new InvalidOperationException("Did not expect the radical code point to be higher than U+8000 for radical " + radicalIndex.ToString() + "."); + + if (isSimplified) + { + builder.SetRadicalInfo(radicalIndex, UpdateRadicalData(builder.GetRadicalInfo(radicalIndex), radicalCodePoint, characterCodePoint)); + } + else + { + builder.SetRadicalInfo(radicalIndex, new CjkRadicalData(radicalCodePoint, characterCodePoint)); + } + } + + if (lastReadRadical != UnicodeInfoBuilder.CjkRadicalCount) + throw new InvalidOperationException("There was not enough data for the 214 CJK radicals."); + } + } + + private static CjkRadicalData UpdateRadicalData(CjkRadicalData traditionalData, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint) + { + return new CjkRadicalData + ( + traditionalData.TraditionalRadicalCodePoint, + traditionalData.TraditionalCharacterCodePoint, + simplifiedRadicalCodePoint, + simplifiedCharacterCodePoint + ); + } + private static async Task ProcessNameAliasesFile(IDataSource ucdSource, UnicodeInfoBuilder builder) { using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(NameAliasesFileName).ConfigureAwait(false), ';')) @@ -475,7 +524,7 @@ namespace System.Unicode.Builder SeparatorFound: ; entry.UnicodeRadicalStrokeCounts.Add(new UnicodeRadicalStrokeCount(byte.Parse(value.Substring(0, index), NumberStyles.None), byte.Parse(value.Substring(index + (isSimplified ? 2 : 1)), NumberStyles.None), isSimplified)); } - break; + break; default: // Ignore unhandled properties for now. break; diff --git a/UnicodeInformation.Builder/UnicodeInfoBuilder.cs b/UnicodeInformation.Builder/UnicodeInfoBuilder.cs index 91bdc42..5baf51d 100644 --- a/UnicodeInformation.Builder/UnicodeInfoBuilder.cs +++ b/UnicodeInformation.Builder/UnicodeInfoBuilder.cs @@ -9,12 +9,15 @@ namespace System.Unicode.Builder { internal class UnicodeInfoBuilder { + public const int CjkRadicalCount = 214; // The number of radicals (214) shouldn't change in the near future… + private readonly Version unicodeVersion; private UnicodeCharacterDataBuilder[] ucdEntries = new UnicodeCharacterDataBuilder[10000]; private int ucdEntryCount; private UnihanCharacterDataBuilder[] unihanEntries = new UnihanCharacterDataBuilder[10000]; private int unihanEntryCount; - private List blockEntries = new List(100); + private readonly List blockEntries = new List(100); + private readonly CjkRadicalData[] cjkRadicals = new CjkRadicalData[CjkRadicalCount]; public UnicodeInfoBuilder(Version unicodeVersion) { @@ -238,6 +241,20 @@ namespace System.Unicode.Builder } } + public void SetRadicalInfo(int radicalIndex, CjkRadicalData data) + { + if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex)); + + cjkRadicals[radicalIndex - 1] = data; + } + + public CjkRadicalData GetRadicalInfo(int radicalIndex) + { + if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex)); + + return cjkRadicals[radicalIndex - 1]; + } + public void AddBlockEntry(UnicodeBlock block) { blockEntries.Add(block); @@ -283,6 +300,20 @@ namespace System.Unicode.Builder { WriteUnicodeBlockToFile(writer, blockEntries[i]); } + writer.Write((byte)CjkRadicalCount); + for (int i = 0; i < cjkRadicals.Length; ++i) + { + var radical = cjkRadicals[i]; + + writer.Write((ushort)(radical.HasSimplifiedForm ? 0x8000 | radical.TraditionalRadicalCodePoint : radical.TraditionalRadicalCodePoint)); + writer.Write((ushort)radical.TraditionalCharacterCodePoint); + + if (radical.HasSimplifiedForm) + { + writer.Write((ushort)radical.SimplifiedRadicalCodePoint); + writer.Write((ushort)radical.SimplifiedCharacterCodePoint); + } + } writer.WriteCodePoint(unihanEntryCount); for (int i = 0; i < unihanEntryCount; ++i) { diff --git a/UnicodeInformation.Builder/UnihanCharacterDataBuilder.cs b/UnicodeInformation.Builder/UnihanCharacterDataBuilder.cs index 4e805f8..f102994 100644 --- a/UnicodeInformation.Builder/UnihanCharacterDataBuilder.cs +++ b/UnicodeInformation.Builder/UnihanCharacterDataBuilder.cs @@ -38,7 +38,7 @@ namespace System.Unicode.Builder public string VietnameseReading { get { return vietnameseReading; } set { vietnameseReading = value; } } public string SimplifiedVariant { get { return simplifiedVariant; } set { simplifiedVariant = value; } } public string TraditionalVariant { get { return traditionalVariant; } set { traditionalVariant = value; } } - public ICollection UnicodeRadicalStrokeCounts { get { return unicodeRadicalStrokeCounts; } } + public IList UnicodeRadicalStrokeCounts { get { return unicodeRadicalStrokeCounts; } } internal UnihanCharacterDataBuilder(int codePoint) { @@ -77,7 +77,7 @@ namespace System.Unicode.Builder { if (unicodeRadicalStrokeCounts.Count == 1) fields |= UnihanFields.UnicodeRadicalStrokeCount; else if (unicodeRadicalStrokeCounts.Count == 2) fields |= UnihanFields.UnicodeRadicalStrokeCountTwice; - else fields |= UnihanFields.UnicodeRadicalStrokeCount | UnihanFields.UnicodeRadicalStrokeCountTwice; + else fields |= UnihanFields.UnicodeRadicalStrokeCountMore; } if (Definition != null) fields |= UnihanFields.Definition; if (MandarinReading != null) fields |= UnihanFields.MandarinReading; @@ -93,6 +93,8 @@ namespace System.Unicode.Builder writer.Write((ushort)fields); writer.WriteCodePoint(UnihanCharacterData.PackCodePoint(codePoint)); + if ((fields & UnihanFields.OtherNumeric) != 0) writer.Write(numericValue); + if ((fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0) { if ((fields & (UnihanFields.UnicodeRadicalStrokeCountMore)) == UnihanFields.UnicodeRadicalStrokeCountMore) @@ -104,7 +106,7 @@ namespace System.Unicode.Builder writer.Write((byte)(radicalStrokeCount.StrokeCount | (radicalStrokeCount.IsSimplified ? 0x80 : 0))); } } - if ((fields & UnihanFields.OtherNumeric) != 0) writer.Write(numericValue); + if ((fields & UnihanFields.Definition) != 0) writer.Write(Definition); if ((fields & UnihanFields.MandarinReading) != 0) writer.Write(MandarinReading); if ((fields & UnihanFields.CantoneseReading) != 0) writer.Write(CantoneseReading); diff --git a/UnicodeInformation.Tests/UnicodeInfoTests.cs b/UnicodeInformation.Tests/UnicodeInfoTests.cs index 830c248..d13d361 100644 --- a/UnicodeInformation.Tests/UnicodeInfoTests.cs +++ b/UnicodeInformation.Tests/UnicodeInfoTests.cs @@ -153,6 +153,47 @@ namespace UnicodeInformation.Tests Assert.AreEqual("Miscellaneous Symbols and Pictographs", UnicodeInfo.GetBlockName(0x1F574)); } + [TestMethod] + public void RadicalStrokeCountTest() + { + var char5E7A = UnicodeInfo.GetCharInfo(0x5E7A); + + Assert.AreNotEqual(0, char5E7A.UnicodeRadicalStrokeCounts); + Assert.AreEqual(false, char5E7A.UnicodeRadicalStrokeCounts[0].IsSimplified); + Assert.AreEqual(char5E7A.UnicodeRadicalStrokeCounts[0].Radical, 52); + Assert.AreEqual(char5E7A.UnicodeRadicalStrokeCounts[0].StrokeCount, 0); + + var char2A6D6 = UnicodeInfo.GetCharInfo(0x2A6D6); + + Assert.AreNotEqual(0, char2A6D6.UnicodeRadicalStrokeCounts); + Assert.AreEqual(false, char2A6D6.UnicodeRadicalStrokeCounts[0].IsSimplified); + Assert.AreEqual(char2A6D6.UnicodeRadicalStrokeCounts[0].Radical, 214); + Assert.AreEqual(char2A6D6.UnicodeRadicalStrokeCounts[0].StrokeCount, 20); + } + + [TestMethod] + public void RadicalInfoTest() + { + var radical1 = UnicodeInfo.GetCjkRadicalInfo(1); + + Assert.AreEqual(false, radical1.HasSimplifiedForm); + Assert.AreEqual('\u2F00', radical1.TraditionalRadicalCodePoint); + Assert.AreEqual('\u4E00', radical1.TraditionalCharacterCodePoint); + Assert.AreEqual('\u2F00', radical1.SimplifiedRadicalCodePoint); + Assert.AreEqual('\u4E00', radical1.SimplifiedCharacterCodePoint); + + var radical214 = UnicodeInfo.GetCjkRadicalInfo(214); + + Assert.AreEqual(false, radical214.HasSimplifiedForm); + Assert.AreEqual('\u2FD5', radical214.TraditionalRadicalCodePoint); + Assert.AreEqual('\u9FA0', radical214.TraditionalCharacterCodePoint); + Assert.AreEqual('\u2FD5', radical214.SimplifiedRadicalCodePoint); + Assert.AreEqual('\u9FA0', radical214.SimplifiedCharacterCodePoint); + + AssertEx.ThrowsExactly(() => UnicodeInfo.GetCjkRadicalInfo(0), nameof(UnicodeInfo.GetCjkRadicalInfo)); + AssertEx.ThrowsExactly(() => UnicodeInfo.GetCjkRadicalInfo(215), nameof(UnicodeInfo.GetCjkRadicalInfo)); + } + #if DEBUG [TestMethod] public void UnihanCodePointPackingTest() diff --git a/UnicodeInformation/CjkRadicalData.cs b/UnicodeInformation/CjkRadicalData.cs new file mode 100644 index 0000000..d673b9c --- /dev/null +++ b/UnicodeInformation/CjkRadicalData.cs @@ -0,0 +1,28 @@ +namespace System.Unicode +{ + internal struct CjkRadicalData + { + public readonly char TraditionalRadicalCodePoint; + public readonly char TraditionalCharacterCodePoint; + public readonly char SimplifiedRadicalCodePoint; + public readonly char SimplifiedCharacterCodePoint; + + internal CjkRadicalData(char radicalCodePoint, char characterCodePoint) + { + TraditionalRadicalCodePoint = radicalCodePoint; + TraditionalCharacterCodePoint = characterCodePoint; + SimplifiedRadicalCodePoint = radicalCodePoint; + SimplifiedCharacterCodePoint = characterCodePoint; + } + + internal CjkRadicalData(char traditionalRadicalCodePoint, char traditionalCharacterCodePoint, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint) + { + TraditionalRadicalCodePoint = traditionalRadicalCodePoint; + TraditionalCharacterCodePoint = traditionalCharacterCodePoint; + SimplifiedRadicalCodePoint = simplifiedCharacterCodePoint; + SimplifiedCharacterCodePoint = simplifiedCharacterCodePoint; + } + + public bool HasSimplifiedForm { get { return SimplifiedRadicalCodePoint != TraditionalRadicalCodePoint || SimplifiedCharacterCodePoint != TraditionalCharacterCodePoint; } } + } +} diff --git a/UnicodeInformation/CjkRadicalInfo.cs b/UnicodeInformation/CjkRadicalInfo.cs new file mode 100644 index 0000000..892d7ea --- /dev/null +++ b/UnicodeInformation/CjkRadicalInfo.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace System.Unicode +{ + public struct CjkRadicalInfo + { + private readonly byte radicalIndex; + private readonly CjkRadicalData radicalData; + + public byte RadicalIndex { get { return radicalIndex; } } + + public char TraditionalRadicalCodePoint { get { return radicalData.TraditionalRadicalCodePoint; } } + public char TraditionalCharacterCodePoint { get { return radicalData.TraditionalCharacterCodePoint; } } + public char SimplifiedRadicalCodePoint { get { return radicalData.SimplifiedRadicalCodePoint; } } + public char SimplifiedCharacterCodePoint { get { return radicalData.SimplifiedCharacterCodePoint; } } + + public bool HasSimplifiedForm { get { return radicalData.HasSimplifiedForm; } } + + internal CjkRadicalInfo(byte radicalIndex, CjkRadicalData radicalData) + { + this.radicalIndex = radicalIndex; + this.radicalData = radicalData; + } + } +} diff --git a/UnicodeInformation/UnicodeInfo.cs b/UnicodeInformation/UnicodeInfo.cs index b72d6f4..fed813a 100644 --- a/UnicodeInformation/UnicodeInfo.cs +++ b/UnicodeInformation/UnicodeInfo.cs @@ -18,17 +18,18 @@ namespace System.Unicode private static readonly UnicodeCharacterData[] unicodeCharacterData; private static readonly UnihanCharacterData[] unihanCharacterData; private static readonly UnicodeBlock[] blocks; + private static readonly CjkRadicalData[] radicals; private static readonly int maxContiguousIndex; static UnicodeInfo() { using (var stream = new DeflateStream(typeof(UnicodeInfo).GetTypeInfo().Assembly.GetManifestResourceStream("ucd.dat"), CompressionMode.Decompress, false)) { - ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out blocks, out maxContiguousIndex); + ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out radicals, out blocks, out maxContiguousIndex); } } - internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out UnicodeBlock[] blocks, out int maxContiguousIndex) + internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out CjkRadicalData[] radicals, out UnicodeBlock[] blocks, out int maxContiguousIndex) { using (var reader = new BinaryReader(stream, Encoding.UTF8)) { @@ -73,6 +74,13 @@ namespace System.Unicode blockEntries[i] = ReadBlockEntry(reader); } + var cjkRadicalEntries = new CjkRadicalData[reader.ReadByte()]; + + for (i = 0; i < cjkRadicalEntries.Length; ++i) + { + cjkRadicalEntries[i] = ReadCjkRadicalInfo(reader); + } + var unihanCharacterDataEntries = new UnihanCharacterData[ReadCodePoint(reader)]; for (i = 0; i < unihanCharacterDataEntries.Length; ++i) @@ -83,6 +91,7 @@ namespace System.Unicode unicodeVersion = fileUnicodeVersion; unicodeCharacterData = unicodeCharacterDataEntries; unihanCharacterData = unihanCharacterDataEntries; + radicals = cjkRadicalEntries; blocks = blockEntries; } } @@ -227,6 +236,17 @@ namespace System.Unicode ); } + private static CjkRadicalData ReadCjkRadicalInfo(BinaryReader reader) + { + char tr; + char tc; + + tr = (char)reader.ReadUInt16(); + tc = (char)reader.ReadUInt16(); + + return (tr & 0x8000) == 0 ? new CjkRadicalData(tr, tc) : new CjkRadicalData((char)(tr & 0x7FFF), tc, (char)reader.ReadUInt16(), (char)reader.ReadUInt16()); + } + private static UnicodeBlock ReadBlockEntry(BinaryReader reader) { return new UnicodeBlock(new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString()); @@ -302,7 +322,7 @@ namespace System.Unicode int minIndex; int maxIndex; - if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unicodeCharacterData.Length - 1].CodePoint) + if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint) { return null; } @@ -340,6 +360,10 @@ namespace System.Unicode return -1; } + /// Gets the name of the Unicode block containing the character. + /// If the character has not been assigned to a block, the value of will be returned. + /// The Unicode code point whose block should be retrieved. + /// The name of the block the code point was assigned to. public static string GetBlockName(int codePoint) { int i = FindBlockIndex(codePoint); @@ -347,11 +371,43 @@ namespace System.Unicode return i >= 0 ? blocks[i].Name : DefaultBlock; } + /// Gets Unicode information on the specified code point. + /// + /// This method will consolidate the data from a few different sources. + /// There are more efficient way of retrieving the data for some properties if only one of those is needed at a time: + /// + /// + /// Property + /// Method + /// + /// + /// Name + /// + /// + /// + /// Category + /// + /// + /// + /// Block + /// + /// + /// + /// + /// The Unicode code point for which the data must be retrieved. + /// The name of the code point, if defined; otherwise. public static UnicodeCharInfo GetCharInfo(int codePoint) { return new UnicodeCharInfo(codePoint, FindUnicodeCodePoint(codePoint), FindUnihanCodePoint(codePoint), GetBlockName(codePoint)); } + /// Gets the category of the specified code point. + /// + /// The name referred to is the unicode General_Category property. + /// If you only need the category of a character, calling this method is faster than calling and retrieving , because there is less information to lookup. + /// + /// The Unicode code point for which the category must be retrieved. + /// The category of the code point. public static UnicodeCategory GetCategory(int codePoint) { var charData = FindUnicodeCodePoint(codePoint); @@ -359,6 +415,9 @@ namespace System.Unicode return charData != null ? charData.Category : UnicodeCategory.OtherNotAssigned; } + /// Gets a display text for the specified code point. + /// The information for the code point. + /// A display text for the code point, which may be the representation of the code point itself. public static string GetDisplayText(UnicodeCharInfo charInfo) { if (charInfo.CodePoint <= 0x0020) return ((char)(0x2400 + charInfo.CodePoint)).ToString(); @@ -366,6 +425,9 @@ namespace System.Unicode else return char.ConvertFromUtf32(charInfo.CodePoint); } + /// Gets a display text for the specified code point. + /// The Unicode code point, for which a display text should be returned. + /// A display text for the code point, which may be the representation of the code point itself. public static string GetDisplayText(int codePoint) { if (codePoint <= 0x0020) return ((char)(0x2400 + codePoint)).ToString(); @@ -373,6 +435,13 @@ namespace System.Unicode else return char.ConvertFromUtf32(codePoint); } + /// Gets the name of the specified code point. + /// + /// The name referred to is the unicode Name property. + /// If you only need the name of a character, calling this method is faster than calling and retrieving , because there is less information to lookup. + /// + /// The Unicode code point for which the name must be retrieved. + /// The name of the code point, if defined; otherwise. public static string GetName(int codePoint) { if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint); @@ -387,6 +456,22 @@ namespace System.Unicode else return null; } + /// Returns information for a CJK radical. + /// The index of the radical. Must be between 1 and . + /// Information on the specified radical. + /// The parameter is out of range. + public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex) + { + return new CjkRadicalInfo(checked((byte)radicalIndex), radicals[radicalIndex - 1]); + } + + /// Returns the number of CJK radicals in the Unicode data. + /// This value will be 214 for the foreseeable future. + public static int CjkRadicalCount { get { return radicals.Length; } } + + /// Gets all the blocks defined in the Unicode data. + /// is not the name of a block, but only a value indicating the abscence of block information for a given code point. + /// An array containing an entry for every block defined in the Unicode data. public static UnicodeBlock[] GetBlocks() { return (UnicodeBlock[])blocks.Clone(); diff --git a/UnicodeInformation/UnicodeInformation.csproj b/UnicodeInformation/UnicodeInformation.csproj index 6d2ccf7..7b8e294 100644 --- a/UnicodeInformation/UnicodeInformation.csproj +++ b/UnicodeInformation/UnicodeInformation.csproj @@ -32,6 +32,8 @@ prompt 4 false + + pdbonly @@ -40,6 +42,8 @@ TRACE prompt 4 + + true @@ -59,6 +63,8 @@ + + diff --git a/UnicodeInformation/UnicodeRadicalStrokeCount.cs b/UnicodeInformation/UnicodeRadicalStrokeCount.cs index 9dcc55b..77b7c72 100644 --- a/UnicodeInformation/UnicodeRadicalStrokeCount.cs +++ b/UnicodeInformation/UnicodeRadicalStrokeCount.cs @@ -22,13 +22,12 @@ namespace System.Unicode internal UnicodeRadicalStrokeCount(byte radical, byte strokeCount, bool isSimplified) { this.radical = radical; + if (isSimplified) strokeCount |= 0x80; this.strokeCount = strokeCount; - - if (isSimplified) this.strokeCount |= 0x80; } public byte Radical { get { return radical; } } - public byte StrokeCount { get { return strokeCount; } } + public byte StrokeCount { get { return (byte)(strokeCount & 0x7F); } } public bool IsSimplified { get { return (strokeCount & 0x80) != 0; } } } } diff --git a/UnicodeInformation/ucd.dat b/UnicodeInformation/ucd.dat index 6117a71..91c6357 100644 Binary files a/UnicodeInformation/ucd.dat and b/UnicodeInformation/ucd.dat differ