26 Commits

Author SHA1 Message Date
GoldenCrystal 3abba328ee Updated the README file. 2014-11-24 23:19:30 +01:00
GoldenCrystal 38a9d989ff Add .nuspec file. 2014-11-24 22:56:12 +01:00
GoldenCrystal f8d468bc94 Prepare for NuGet publishing. 2014-11-24 22:53:33 +01:00
GoldenCrystal 0d3239d700 Added tests for CJK radicals, NumericType, NumericValue, Hangul syllable names. 2014-11-24 22:01:31 +01:00
GoldenCrystal 84e1a40612 Renamed UnicodeCharacterRange to UnicodeCodePointRange, and added a few unit tests. 2014-11-24 21:47:06 +01:00
GoldenCrystal 78baae7ff2 Added support for CJK radicals.
Addded CJK radical & stroke count information to the UI.
2014-11-24 20:09:59 +01:00
GoldenCrystal 475e9c5e44 Added support for kRSUnicode/Unicode_Radical_Stroke. 2014-11-24 02:36:09 +01:00
GoldenCrystal 76e5b5f0ba Added ValueNameAttribute on UnicodeCharInfo properties. Those reference the name of the associated Unicode property. 2014-11-24 02:20:18 +01:00
GoldenCrystal 2fd517a286 Included a cleaned source file for the icon. 2014-11-24 00:55:50 +01:00
GoldenCrystal 4f03ba85d9 Exposed cross-references, and added them to the UI. 2014-11-24 00:24:55 +01:00
GoldenCrystal 95fd83cb6d Imported related code points (aka cross-references) from NamesList.txt. 2014-11-23 18:44:32 +01:00
GoldenCrystal 21253a170e Slightly improved the lookup for character data. 2014-11-23 16:38:52 +01:00
GoldenCrystal ee8c1b1f6e Updated the documentation. 2014-11-21 17:33:52 +01:00
GoldenCrystal 2324d2c272 Rebuilt the data file, and fixed the handling of name aliases. 2014-11-21 17:04:55 +01:00
GoldenCrystal b148e69ca0 Added the code to parse NameAliases.txt an updated the UI. 2014-11-21 16:51:09 +01:00
GoldenCrystal d5131ef008 Exposed the name aliases and refactored argument exceptions. 2014-11-21 16:25:57 +01:00
GoldenCrystal 343dc823cf Included name aliases in the data file. 2014-11-21 16:02:19 +01:00
GoldenCrystal 4119824ffc First tentative of name alias encoding. 2014-11-21 15:41:27 +01:00
GoldenCrystal 83fb677dc2 Updated the implementation of Unicode blocks, and added tests. 2014-11-20 22:00:07 +01:00
GoldenCrystal c895b2e627 Small non-bug fixes on HangulInfo class. 2014-11-20 21:42:04 +01:00
GoldenCrystal 694a749046 Added hangul syllable naming algorithm from Unicode 7.0. 2014-11-20 21:26:50 +01:00
GoldenCrystal 5c47c98b18 Added a few unit tests. 2014-11-17 23:29:51 +01:00
GoldenCrystal 3893b22fc0 Fix UnicodeCharInfo for non assigned characters. 2014-11-17 21:10:25 +01:00
GoldenCrystal ea1a498aff Added a placeholder text in the text box, and made a few other UI tweaks. 2014-11-17 20:08:29 +01:00
GoldenCrystal 11f2619411 Added an icon. 2014-11-16 22:47:30 +01:00
GoldenCrystal 9c3cd4207b Replaced spaces by tabs on files with incoherent indentations. 2014-11-16 21:27:57 +01:00
69 changed files with 2262 additions and 456 deletions
+19
View File
@@ -0,0 +1,19 @@
using System.Resources;
using System.Reflection;
using System.Runtime.InteropServices;
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
[assembly: AssemblyCompany("Fabien Barbier")]
[assembly: AssemblyProduct(".NET Unicode Information")]
[assembly: AssemblyCopyright("Copyright © Fabien Barbier 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+18 -6
View File
@@ -1,15 +1,23 @@
.NET Unicode Information Library
========================
Unicode Character Inspector & .NET Unicode Information Library
==============================================================
Summary
-------
This projects provides access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
Included, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
This projects has two parts.
One is a library, providing access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
The other, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
Using the Unicode Character Inspector application
-------------------------------------------------
Simply launch the application, then type or paste some text in the text box on the top of the window.
The code points will be displayed in the list on the left side. Select one of them to display the associated information in the bottom-right pane.
![Screenshot of Unicode Character Inspector](docs/uci-00.png)
Compiling and using the project
-------------------------------
### Using the UnicodeInformation library
Using the library is as easy as including it in your project. You will find all the good stuff in the System.Unicode namespace.
Grab the latest version of the package on NuGet: https://www.nuget.org/packages/UnicodeInformation/.
Once the library is installed in your project, you will find everything you need in the System.Unicode namespace.
Let's see a simple example:
@@ -56,13 +64,14 @@ This library includes a subset of the official [Unicode Character Database](http
* Bidi_Class
* Decomposition_Type
* Decomposition_Mapping
* Numeric_Type (*)
* Numeric_Type (See also kAccountingNumeric/kOtherNumeric/kPrimaryNumeric. Those will set Numeric_Type to Numeric.)
* Numeric_Value
* Bidi_Mirrored
* Unicode_1_Name
* Simple_Uppercase_Maping
* Simple_Lowercase_Mapping
* Simple_Titlecase_Mapping
* Name_Alias
* Block
* ASCII_Hex_Digit
* Bidi_Control
@@ -115,6 +124,8 @@ This library includes a subset of the official [Unicode Character Database](http
* ID_Continue
* XID_Start
* XID_Continue
* Unicode_Radical_Stroke (This is actually kRSUnicode from the Unihan database)
* Code point cross references extracted from NamesList.txt
NB: The UCD property ISO_Comment will never be included since this one is empty in all new Unicode versions.
@@ -122,6 +133,7 @@ NB: The UCD property ISO_Comment will never be included since this one is empty
* kAccountingNumeric
* kOtherNumeric
* kPrimaryNumeric
* kRSUnicode
* kDefinition
* kMandarin
* kCantonese
+4
View File
@@ -7,5 +7,9 @@
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
<local:Utf32ToDisplayTextConverter x:Key="Utf32ToDisplayTextConverter" />
<local:Utf32ToNameConverter x:Key="Utf32ToNameConverter" />
<local:StringToUtf32Converter x:Key="StringToUtf32Converter" />
<local:RadicalStrokeCountToCharConverter x:Key="RadicalStrokeCountToCharConverter" />
</Application.Resources>
</Application>
+1 -4
View File
@@ -1,10 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace UnicodeCharacterInspector
{
@@ -38,7 +35,7 @@ namespace UnicodeCharacterInspector
storage = value;
NotifyPropertyChanged(propertyName);
return true;
}
}
return false;
}
}
@@ -47,12 +47,13 @@ namespace UnicodeCharacterInspector
{
codePoint = 0;
characterInfo = UnicodeInfo.GetCharInfo(0);
}
}
NotifyPropertyChanged();
UpdateDisplayText();
NotifyPropertyChanged(nameof(CodePoint));
NotifyPropertyChanged(nameof(Name));
NotifyPropertyChanged(nameof(NameAliases));
NotifyPropertyChanged(nameof(OldName));
NotifyPropertyChanged(nameof(Definition));
NotifyPropertyChanged(nameof(Category));
@@ -66,6 +67,8 @@ namespace UnicodeCharacterInspector
NotifyPropertyChanged(nameof(NumericValue));
NotifyPropertyChanged(nameof(ContributoryProperties));
NotifyPropertyChanged(nameof(CoreProperties));
NotifyPropertyChanged(nameof(RadicalStrokeCounts));
NotifyPropertyChanged(nameof(CrossReferences));
NotifyPropertyChanged(nameof(MandarinReading));
NotifyPropertyChanged(nameof(CantoneseReading));
NotifyPropertyChanged(nameof(JapaneseKunReading));
@@ -101,6 +104,11 @@ namespace UnicodeCharacterInspector
get { return character != null ? characterInfo.Name : null; }
}
public UnicodeNameAliasCollection NameAliases
{
get { return character != null ? characterInfo.NameAliases : new UnicodeNameAliasCollection(); }
}
public string OldName
{
get { return character != null ? characterInfo.OldName : null; }
@@ -166,6 +174,16 @@ 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(); }
}
public string MandarinReading
{
get { return character != null ? characterInfo.MandarinReading : null; }
@@ -2,10 +2,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Unicode;
namespace UnicodeCharacterInspector
@@ -23,7 +19,7 @@ namespace UnicodeCharacterInspector
CodePoint = codePoint;
Character = char.ConvertFromUtf32(codePoint);
DisplayText = UnicodeInfo.GetDisplayText(codePoint);
}
}
}
private class CharacterCollection : INotifyCollectionChanged, IList<CharacterViewModel>
@@ -74,8 +70,8 @@ namespace UnicodeCharacterInspector
public void CopyTo(CharacterViewModel[] array, int arrayIndex)
{
if (array == null) throw new ArgumentNullException("array");
if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex");
if (array == null) throw new ArgumentNullException(nameof(array));
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
if (array.Length < arrayIndex + owner.codePoints.Length) throw new ArgumentException();
for (int i = 0, j = arrayIndex; i < owner.codePoints.Length; ++i, ++j)
@@ -108,7 +104,7 @@ namespace UnicodeCharacterInspector
public CharacterInspectorViewModel()
{
characterCollection = new CharacterCollection(this);
}
}
private void NotifyCollectionChanged(NotifyCollectionChangedAction action)
{
@@ -164,7 +160,7 @@ namespace UnicodeCharacterInspector
NotifyPropertyChanged(nameof(SelectedCharacter));
selectedCharacterInfo.Character = null;
}
}
}
}
public ICollection<CharacterViewModel> Characters { get { return characterCollection; } }
@@ -175,7 +171,7 @@ namespace UnicodeCharacterInspector
set
{
if (selectedCharacterIndex < -1 || selectedCharacterIndex >= codePoints.Length)
throw new ArgumentOutOfRangeException("value");
throw new ArgumentOutOfRangeException(nameof(value));
if (value != selectedCharacterIndex)
{
+82 -44
View File
@@ -13,7 +13,7 @@
<Window.DataContext>
<local:CharacterInspectorViewModel />
</Window.DataContext>
<Grid Margin="10">
<Grid Margin="10">
<Grid.Resources>
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource ResourceKey={x:Type Label}}">
<Setter Property="Margin" Value="3" />
@@ -37,7 +37,7 @@
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsReturn="True" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsTab="True" AcceptsReturn="True" local:Placeholder.Text="Text to analyse" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
<ListBox Grid.Row="1" Grid.RowSpan="3" ItemsSource="{Binding Characters}" SelectedIndex="{Binding SelectedCharacterIndex}">
<ListBox.ItemTemplate>
<DataTemplate>
@@ -45,7 +45,7 @@
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="1" Grid.Column="1" TextOptions.TextFormattingMode="Ideal" TextOptions.TextRenderingMode="Grayscale" Text="{Binding SelectedCharacterInfo.DisplayText}" FontSize="96" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="1" TextOptions.TextHintingMode="Fixed" TextOptions.TextFormattingMode="Ideal" TextOptions.TextRenderingMode="Grayscale" Text="{Binding SelectedCharacterInfo.DisplayText}" FontSize="96" HorizontalAlignment="Center" VerticalAlignment="Center" />
<ScrollViewer Grid.Row="2" Grid.Column="1" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.Resources>
@@ -53,6 +53,9 @@
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Margin" Value="6" />
</Style>
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource ResourceKey={x:Type ItemsControl}}">
<Setter Property="Margin" Value="6" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width ="Auto" />
@@ -82,6 +85,9 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CodePoint, Converter={StaticResource NullToVisibilityConverter}}" Text="Code Point" />
@@ -90,47 +96,79 @@
<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Name, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Name}" />
<TextBlock Grid.Row="2" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="Old Name" />
<TextBlock Grid.Row="2" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.OldName}" />
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
<TextBlock Grid.Row="3" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.SimplifiedVariant}" />
<TextBlock Grid.Row="4" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
<TextBlock Grid.Row="4" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
<TextBlock Grid.Row="12" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
<TextBlock Grid.Row="13" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
<TextBlock Grid.Row="21" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Contributory Properties" />
<TextBlock Grid.Row="21" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
<TextBlock Grid.Row="22" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Core Properties" />
<TextBlock Grid.Row="22" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Aliases" />
<ItemsControl Grid.Row="3" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.NameAliases}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="WrapWithOverflow">
<Run Text="{Binding Name, Mode=OneTime}" /> (<Run Text="{Binding Kind, Mode=OneTime}" />)
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Radical &amp; Stroke Count" />
<ItemsControl Grid.Row="4" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.RadicalStrokeCounts}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="WrapWithOverflow">
Radical <Run Text="{Binding Radical, Mode=OneTime}" /> (<Run Text="{Binding Mode=OneTime, Converter={StaticResource RadicalStrokeCountToCharConverter}}" />), <Run Text="{Binding StrokeCount, Mode=OneTime}" /> strokes
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}">
“<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay}" />” U+<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay, Converter={StaticResource StringToUtf32Converter}, StringFormat=X4}" />
</TextBlock>
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
<TextBlock Grid.Row="12" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
<TextBlock Grid.Row="13" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
<TextBlock Grid.Row="21" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
<TextBlock Grid.Row="21" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
<TextBlock Grid.Row="22" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
<TextBlock Grid.Row="22" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
<TextBlock Grid.Row="23" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Contributory Properties" />
<TextBlock Grid.Row="23" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
<TextBlock Grid.Row="24" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Core Properties" />
<TextBlock Grid.Row="24" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
<TextBlock Grid.Row="25" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Cross-References" />
<ItemsControl Grid.Row="25" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.CrossReferences}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="WrapWithOverflow">
“<Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToDisplayTextConverter}}" />” U+<Run Text="{Binding Mode=OneTime, StringFormat=X4}" /> <Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToNameConverter}}" />
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</ScrollViewer>
</Grid>
</Grid>
</Window>
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
+166
View File
@@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
namespace UnicodeCharacterInspector
{
// Inspired by http://stackoverflow.com/questions/833943/watermark-hint-text-placeholder-textbox-in-wpf
internal static partial class Placeholder
{
public static string GetText(DependencyObject obj)
{
return (string)obj.GetValue(TextProperty);
}
public static void SetText(DependencyObject obj, string value)
{
obj.SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(Placeholder), new PropertyMetadata(OnTextChanged));
private static readonly HashSet<Control> handledControls = new HashSet<Control>();
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as TextBoxBase;
if (d == null) return;
if (e.NewValue == null || "".Equals(e.NewValue)) UnregisterControl(control);
else UpdateControl(control, (string)e.NewValue);
}
private static void OnControlLoaded(object sender, RoutedEventArgs e)
{
var control = (Control)sender;
UpdateControl(control, GetText(control));
}
private static void OnTextBoxGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
{
var control = (Control)sender;
RemoveAdorner(control);
}
private static void UpdateControl(Control control, string placeholderText)
{
if (handledControls.Add(control))
{
RegisterControl(control);
}
if (IsEmpty(control))
{
var adorner = GetAdorner(control) ?? AddAdorner(control);
if (adorner != null) adorner.Text = placeholderText;
}
else
{
RemoveAdorner(control);
}
}
private static void RegisterControl(Control control)
{
control.Loaded += OnControlLoaded;
var textBox = control as TextBoxBase;
if (textBox != null) RegisterTextBox(textBox);
}
private static void RegisterTextBox(TextBoxBase textBox)
{
textBox.GotKeyboardFocus += OnTextBoxGotKeyboardFocus;
textBox.LostKeyboardFocus += OnControlLoaded;
}
private static void UnregisterControl(Control control)
{
if (handledControls.Remove(control))
{
control.Loaded -= OnControlLoaded;
var textBox = control as TextBoxBase;
if (textBox != null) UnregisterTextBox(textBox);
RemoveAdorner(control);
}
}
private static void UnregisterTextBox(TextBoxBase textBox)
{
textBox.GotKeyboardFocus -= OnTextBoxGotKeyboardFocus;
textBox.LostKeyboardFocus -= OnControlLoaded;
}
private static bool IsEmpty(Control control)
{
var textBox = control as TextBox;
if (textBox != null) return string.IsNullOrEmpty(textBox.Text);
return false;
}
private static PlaceholderAdorner GetAdorner(Control control)
{
var layer = AdornerLayer.GetAdornerLayer(control);
if (layer != null)
{
var adorners = layer.GetAdorners(control);
if (adorners != null)
{
foreach (var adorner in adorners)
{
var placeholder = adorner as PlaceholderAdorner;
if (placeholder != null) return placeholder;
}
}
}
return null;
}
private static PlaceholderAdorner AddAdorner(Control control)
{
var layer = AdornerLayer.GetAdornerLayer(control);
if (layer == null) return null;
var placeholder = new PlaceholderAdorner(control);
layer.Add(placeholder);
return placeholder;
}
private static void RemoveAdorner(Control control)
{
var layer = AdornerLayer.GetAdornerLayer(control);
if (layer == null) return;
var adorners = layer.GetAdorners(control);
if (adorners == null) return;
foreach (var adorner in adorners)
{
var placeholder = adorner as PlaceholderAdorner;
if (placeholder != null)
{
layer.Remove(placeholder);
return;
}
}
}
}
}
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
namespace UnicodeCharacterInspector
{
internal static partial class Placeholder
{
private sealed class PlaceholderAdorner : Adorner
{
public string Text { get; set; }
public PlaceholderAdorner(UIElement adornedElement)
: base(adornedElement)
{
IsHitTestVisible = false;
}
protected override Visual GetVisualChild(int index) { throw new InvalidOperationException(); }
protected override int VisualChildrenCount { get { return 0; } }
protected override void OnRender(DrawingContext drawingContext)
{
var control = ((Control)AdornedElement);
Rect adornedElementRect = new Rect(AdornedElement.RenderSize);
drawingContext.DrawText
(
new FormattedText
(
Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface
(
control.FontFamily,
control.FontStyle,
control.FontWeight,
control.FontStretch,
SystemFonts.MessageFontFamily
),
control.FontSize,
SystemColors.GrayTextBrush
),
// The offsets where experimentally determined on a Windows 8.1 machine. I'm willing to accept anything better. 😉
new Point(control.BorderThickness.Left + control.Padding.Left + 5, control.BorderThickness.Top + control.Padding.Top + 3)
);
}
}
}
}
@@ -1,35 +1,11 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnicodeCharacterInspector")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnicodeCharacterInspector")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: AssemblyTitle("Unicode Character Inspector")]
[assembly: AssemblyDescription("A character inspector for Unicode text.")]
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
@@ -39,17 +15,3 @@ using System.Windows;
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -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();
}
}
}
@@ -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();
}
}
}
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{04E97F21-EF04-441F-83CF-2E71F3AAB089}</ProjectGuid>
<OutputType>WinExe</OutputType>
@@ -39,6 +39,12 @@
<PropertyGroup>
<ApplicationManifest>App.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>UnicodeCharacterInspector.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<UICulture>en-US</UICulture>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -63,6 +69,9 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="..\AssemblyInfo.Common.cs">
<Link>Properties\AssemblyInfo.Common.cs</Link>
</Compile>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
@@ -70,6 +79,14 @@
<Compile Include="BindableObject.cs" />
<Compile Include="CharacterInfoViewModel.cs" />
<Compile Include="CharacterInspectorViewModel.cs" />
<Compile Include="Placeholder.cs" />
<Compile Include="PlaceholderAdorner.cs">
<DependentUpon>Placeholder.cs</DependentUpon>
</Compile>
<Compile Include="RadicalStrokeCountToCharConverter.cs" />
<Compile Include="StringToUtf32Converter.cs" />
<Compile Include="Utf32ToNameConverter.cs" />
<Compile Include="Utf32ToDisplayTextConverter.cs" />
<Compile Include="ZeroToVisibilityConverter.cs" />
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
@@ -93,6 +110,9 @@
<Name>UnicodeInformation</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="UnicodeCharacterInspector.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="16"
height="16"
id="svg2">
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-1036.3622)"
id="layer1">
<path
d="m 2.5,1.5 2,2"
transform="translate(0,1036.3622)"
id="path3763"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 1.5,1039.8622 5,0 c -1,2 -3,5 -5,6"
id="path3765"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 4.5,14.5 0,-7.5 2,3.5"
transform="translate(0,1036.3622)"
id="path3767"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 8.5,1037.8622 0,9 5,0 0,-9 z"
id="path3769"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 8.5,1040.8622 5,0"
id="path3771"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 8.5,1043.8622 5,0"
id="path3773"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 9.5,1046.8622 c 0,0 1,4 -3,4"
id="path3775"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
<path
d="m 11.5,1046.8622 0,2 c 0,2 0.5,2 1.5,2 1.5,0 1.5,-1 1.5,-2"
id="path3777"
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

@@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Unicode;
using System.Windows.Data;
namespace UnicodeCharacterInspector
{
internal sealed class Utf32ToDisplayTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null ? UnicodeInfo.GetDisplayText((int)value) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Unicode;
using System.Windows.Data;
namespace UnicodeCharacterInspector
{
internal sealed class Utf32ToNameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null ? UnicodeInfo.GetName((int)value) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
@@ -11,7 +11,7 @@ namespace System.Unicode.Builder
{
public static void WriteUInt24(this BinaryWriter writer, int value)
{
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException("value");
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException(nameof(value));
writer.Write((byte)(value));
writer.Write((byte)(value >> 8));
@@ -27,7 +27,7 @@ namespace System.Unicode.Builder
/// <param name="value">The value to write</param>
public static void WriteCodePoint(this BinaryWriter writer, int value)
{
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException("value");
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException(nameof(value));
if (value < 0xA0) writer.Write((byte)value);
else if (value < 0x20A0)
@@ -50,5 +50,40 @@ namespace System.Unicode.Builder
writer.Write((byte)value);
}
}
/// <summary>Writes a character name alias.</summary>
/// <remarks>We assume that character names will not exceed 64 bytes in length.</remarks>
/// <param name="writer">The writer to use.</param>
/// <param name="nameAlias">The name alias value to write.</param>
public static void WriteNameAliasToFile(this BinaryWriter writer, UnicodeNameAlias nameAlias)
{
writer.Write(nameAlias.Name);
writer.Write((byte)nameAlias.Kind);
}
/// <summary>Writes a character name, packing two information bits along with the length.</summary>
/// <remarks>We assume that character names will not exceed 128 bytes in length.</remarks>
/// <param name="writer">The writer to use.</param>
/// <param name="name">The name to write.</param>
public static void WriteNamePropertyToFile(this BinaryWriter writer, string name)
{
var bytes = Encoding.UTF8.GetBytes(name);
if (bytes.Length > 128) throw new InvalidOperationException("Did not expect UTF-8 encoded name to be longer than 128 bytes.");
writer.Write((byte)(name.Length - 1)); // The most significant bit will always be cleared, because it will be used for other cases.
writer.Write(bytes);
}
/// <summary>Writes a 6 bits length packed with two extra bits.</summary>
/// <remarks>The parameters have a restricted range, which must be respected.</remarks>
/// <param name="writer">The writer used to perform the operation.</param>
/// <param name="extraBits">The value of the two extra bits.</param>
/// <param name="length">The length to write.</param>
public static void WritePackedLength(this BinaryWriter writer, byte extraBits, int length)
{
if (extraBits > 3) throw new ArgumentOutOfRangeException(nameof(extraBits));
if (length < 1 || length > 64) throw new ArgumentOutOfRangeException(nameof(length));
writer.Write((byte)((extraBits << 6) | (length - 1)));
}
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode.Builder
{
public static class CharExtensions
{
public static bool IsHexDigit(this char c)
{
return c >= '0' && c <= 'f' && (c <= '9' || c <= 'F' && c >= 'A' || c >= 'a');
}
}
}
@@ -36,7 +36,7 @@ namespace System.Unicode.Builder
index = 0;
}
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
int charIndex = 0;
while (index < s.Length && charIndex < 35)
+1 -1
View File
@@ -24,7 +24,7 @@ namespace System.Unicode.Builder
{
this.httpClient = new HttpClient();
this.baseUri = baseUri;
}
}
public void Dispose()
{
+24 -11
View File
@@ -13,7 +13,7 @@ namespace System.Unicode.Builder
{
public const string UnihanDirectoryName = "Unihan";
public const string UnihanArchiveName = "Unihan.zip";
public const string directoryName = "UCD";
public const string UcdDirectoryName = "UCD";
public const string UcdArchiveName = "UCD.zip";
public static readonly string[] ucdRequiredFiles = new[]
@@ -21,8 +21,11 @@ namespace System.Unicode.Builder
"UnicodeData.txt",
"PropList.txt",
"DerivedCoreProperties.txt",
"Blocks.txt",
"Jamo.txt",
"CJKRadicals.txt",
//"Jamo.txt", // Not used right now, as the hangul syllable algorithm implementation takes care of this.
"NameAliases.txt",
"NamesList.txt",
"Blocks.txt",
};
public static readonly string[] unihanRequiredFiles = new[]
@@ -30,20 +33,30 @@ namespace System.Unicode.Builder
"Unihan_NumericValues.txt",
"Unihan_Readings.txt",
"Unihan_Variants.txt",
"Unihan_IRGSources.txt",
};
private static HttpMessageHandler httpMessageHandler;
// The only purpose of this is for tests…
internal static HttpMessageHandler HttpMessageHandler
{
get { return httpMessageHandler ?? (httpMessageHandler = new HttpClientHandler()); }
set { httpMessageHandler = value != null ? value : new HttpClientHandler(); }
}
private static byte[] DownloadDataArchive(string archiveName)
{
using (var httpClient = new HttpClient())
using (var httpClient = new HttpClient(HttpMessageHandler))
{
return httpClient.GetByteArrayAsync(HttpDataSource.UnicodeCharacterDataUri + archiveName).Result;
}
}
}
internal static IDataSource GetDataSource(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
{
string baseDirectory = Environment.CurrentDirectory;
string dataDirectory = Path.Combine(baseDirectory, Program.directoryName);
string dataDirectory = Path.Combine(baseDirectory, UcdDirectoryName);
string dataArchiveFileName = Path.Combine(baseDirectory, archiveName);
if (shouldDownload != true)
@@ -79,7 +92,7 @@ namespace System.Unicode.Builder
return new ZipDataSource(File.OpenRead(dataArchiveFileName));
}
}
}
}
if (shouldDownload != false)
{
@@ -91,7 +104,7 @@ namespace System.Unicode.Builder
try
{
stream.Write(dataArchiveData, 0, dataArchiveData.Length);
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
if (shouldExtract == true)
{
@@ -120,13 +133,13 @@ namespace System.Unicode.Builder
}
throw new InvalidOperationException();
}
}
private static void Main(string[] args)
{
UnicodeInfoBuilder data;
using (var ucdSource = GetDataSource(UcdArchiveName, directoryName, ucdRequiredFiles, null, null, null))
using (var ucdSource = GetDataSource(UcdArchiveName, UcdDirectoryName, ucdRequiredFiles, null, null, null))
using (var unihanSource = GetDataSource(UnihanArchiveName, UnihanDirectoryName, unihanRequiredFiles, null, null, null))
{
data = UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource).Result;
@@ -134,6 +147,6 @@ namespace System.Unicode.Builder
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
data.WriteToStream(stream);
}
}
}
}
@@ -1,37 +1,8 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnicodeInformation.Builder")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnicodeInformation.Builder")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8dfdee6c-4f0d-4de1-b346-574cb56d2b8b")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyDescription("Data file builder for the .NET Unicode Information Library.")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
@@ -10,7 +10,7 @@ namespace System.Unicode.Builder
{
public sealed class UnicodeCharacterDataBuilder
{
private readonly UnicodeCharacterRange codePointRange;
private readonly UnicodeCodePointRange codePointRange;
private string name;
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
private CanonicalCombiningClass canonicalCombiningClass;
@@ -26,9 +26,10 @@ namespace System.Unicode.Builder
private ContributoryProperties contributoryProperties;
private CoreProperties coreProperties;
private List<int> relatedCodePoints = new List<int>();
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
private readonly List<int> crossRerefences = new List<int>();
public UnicodeCharacterRange CodePointRange { get { return codePointRange; } }
public UnicodeCodePointRange CodePointRange { get { return codePointRange; } }
public string Name
{
@@ -36,6 +37,8 @@ namespace System.Unicode.Builder
set { name = value; }
}
public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
public UnicodeCategory Category
{
get { return category; }
@@ -43,7 +46,7 @@ namespace System.Unicode.Builder
{
if (!Enum.IsDefined(typeof(UnicodeCategory), value))
{
throw new ArgumentOutOfRangeException("value");
throw new ArgumentOutOfRangeException(nameof(value));
}
category = value;
}
@@ -121,14 +124,14 @@ namespace System.Unicode.Builder
set { coreProperties = value; }
}
public ICollection<int> RelatedCodePoints { get { return relatedCodePoints; } }
public IList<int> CrossRerefences { get { return crossRerefences; } }
public UnicodeCharacterDataBuilder(int codePoint)
: this(new UnicodeCharacterRange(codePoint))
: this(new UnicodeCodePointRange(codePoint))
{
}
public UnicodeCharacterDataBuilder(UnicodeCharacterRange codePointRange)
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
{
this.codePointRange = codePointRange;
this.category = UnicodeCategory.OtherNotAssigned;
@@ -138,36 +141,40 @@ namespace System.Unicode.Builder
{
return new UnicodeCharacterData
(
codePointRange,
CodePointRange,
Name,
category,
canonicalCombiningClass,
bidirectionalClass,
characterDecompositionMapping.DecompositionType,
characterDecompositionMapping.DecompositionMapping,
numericType,
numericValue,
bidirectionalMirrored,
oldName,
simpleUpperCaseMapping,
simpleLowerCaseMapping,
simpleTitleCaseMapping,
contributoryProperties,
coreProperties,
relatedCodePoints.Count > 0 ? relatedCodePoints.ToArray() : null
NameAliases.Count > 0 ? NameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
Category,
CanonicalCombiningClass,
BidirectionalClass,
CharacterDecompositionMapping.DecompositionType,
CharacterDecompositionMapping.DecompositionMapping,
NumericType,
NumericValue,
BidirectionalMirrored,
OldName,
SimpleUpperCaseMapping,
SimpleLowerCaseMapping,
SimpleTitleCaseMapping,
ContributoryProperties,
CoreProperties,
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
);
}
internal void WriteToFile(BinaryWriter writer)
{
if (nameAliases.Count > 64) throw new InvalidDataException("Cannot handle more than 64 name aliases.");
UcdFields fields = default(UcdFields);
if (!codePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
if (name != null) fields |= UcdFields.Name;
if (name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category;
if (canonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
/*if (bidirectionalClass != 0)*/fields |= UcdFields.BidirectionalClass;
/*if (bidirectionalClass != 0)*/
fields |= UcdFields.BidirectionalClass;
if (characterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
fields |= (UcdFields)((int)numericType << 6);
if (bidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
@@ -177,13 +184,35 @@ namespace System.Unicode.Builder
if (simpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
if (contributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
if (coreProperties != 0) fields |= UcdFields.CoreProperties;
if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences;
writer.Write((ushort)fields);
writer.WriteCodePoint(codePointRange.FirstCodePoint);
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
if ((fields & UcdFields.Name) != 0) writer.Write(name);
if ((fields & UcdFields.Name) != 0)
{
// We write the names by optimizing for the common case.
// i.e. Most characters have only one name.
// The first 8 bit sequence will encore either the length of the name property alone,
// or the number of aliases and a bit indicating the presence of the name property.
if (nameAliases.Count > 0)
{
writer.WritePackedLength((byte)(name != null ? 3 : 2), nameAliases.Count);
if (name != null)
writer.WriteNamePropertyToFile(name);
foreach (var nameAlias in nameAliases)
writer.WriteNameAliasToFile(nameAlias);
}
else
{
writer.WriteNamePropertyToFile(name);
}
}
if ((fields & UcdFields.Category) != 0) writer.Write((byte)category);
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)canonicalCombiningClass);
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)bidirectionalClass);
@@ -203,6 +232,12 @@ namespace System.Unicode.Builder
if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(simpleTitleCaseMapping);
if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)contributoryProperties);
if ((fields & UcdFields.CoreProperties) != 0) writer.WriteUInt24((int)coreProperties);
if ((fields & UcdFields.CrossRerefences) != 0)
{
writer.Write(checked((byte)(crossRerefences.Count - 1)));
foreach (int crossReference in crossRerefences)
writer.WriteCodePoint(crossReference);
}
}
}
}
@@ -59,7 +59,7 @@ namespace System.Unicode.Builder
hasField = true;
goto Completed;
}
}
}
else
{
return false;
@@ -82,9 +82,9 @@ namespace System.Unicode.Builder
} while (RefillBuffer());
hasField = false;
Completed: ;
Completed:;
return hasField;
}
}
private string ReadFieldInternal(bool trim)
{
@@ -121,7 +121,7 @@ namespace System.Unicode.Builder
{
byte b = byteBuffer[index];
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
{
endOffset = index;
hasField = false;
@@ -192,7 +192,7 @@ namespace System.Unicode.Builder
{
byte b = byteBuffer[index];
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
{
hasField = false;
return true;
@@ -13,10 +13,14 @@ 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";
public const string UnihanReadingsFileName = "Unihan_Readings.txt";
public const string UnihanVariantsFileName = "Unihan_Variants.txt";
public const string UnihanNumericValuesFileName = "Unihan_NumericValues.txt";
public const string UnihanIrgSourcesFileName = "Unihan_IRGSources.txt";
private static string ParseSimpleCaseMapping(string mapping)
{
@@ -37,10 +41,14 @@ 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);
await ProcessUnihanReadings(unihanSource, builder).ConfigureAwait(false);
await ProcessUnihanVariants(unihanSource, builder).ConfigureAwait(false);
await ProcessUnihanNumericValues(unihanSource, builder).ConfigureAwait(false);
await ProcessUnihanIrgSources(unihanSource, builder).ConfigureAwait(false);
return builder;
}
@@ -53,7 +61,7 @@ namespace System.Unicode.Builder
while (reader.MoveToNextLine())
{
var codePoint = new UnicodeCharacterRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
var codePoint = new UnicodeCodePointRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
string name = reader.ReadField();
@@ -71,9 +79,9 @@ namespace System.Unicode.Builder
{
if (rangeStartCodePoint < 0) throw new InvalidDataException("Invalid range data in UnicodeData.txt.");
codePoint = new UnicodeCharacterRange(rangeStartCodePoint, codePoint.LastCodePoint);
codePoint = new UnicodeCodePointRange(rangeStartCodePoint, codePoint.LastCodePoint);
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
rangeStartCodePoint = -1;
}
@@ -170,7 +178,7 @@ namespace System.Unicode.Builder
{
ContributoryProperties property;
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
{
builder.SetProperties(property, range);
@@ -187,7 +195,7 @@ namespace System.Unicode.Builder
{
CoreProperties property;
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
{
builder.SetProperties(property, range);
@@ -196,13 +204,167 @@ 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), ';'))
{
while (reader.MoveToNextLine())
{
var ucd = builder.GetUcd(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
string name = reader.ReadField();
string kindName = reader.ReadField();
UnicodeNameAliasKind kind;
if (!EnumHelper<UnicodeNameAliasKind>.TryGetNamedValue(kindName, out kind))
throw new InvalidDataException("Unrecognized name alias: " + kindName + ".3");
ucd.NameAliases.Add(new UnicodeNameAlias(name, kind));
}
}
}
private static async Task ProcessNamesListFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
using (var reader = new StreamReader(await ucdSource.OpenDataFileAsync(NamesListFileName).ConfigureAwait(false), Encoding.UTF8, false))
{
string line;
var characterData = null as UnicodeCharacterDataBuilder;
while ((line = reader.ReadLine()) != null)
{
if (line.Length == 0)
{
characterData = null;
continue;
}
if (characterData != null && line.Length > 3 && line[0] == '\t')
{
if (line[1] == 'x')
{
// We should get at least 7 characters for a valid line: <tab> "x" <space> [0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]
if (line.Length < 7)
{
characterData = null;
continue;
}
if (line[2] != ' ') throw new InvalidDataException();
int length;
if (line[3].IsHexDigit())
{
length = line.IndexOf(' ', 3);
if (length < 0) length = line.Length;
length -= 3;
characterData.CrossRerefences.Add(int.Parse(line.Substring(3, length), NumberStyles.HexNumber));
}
else if (line[3] == '(')
{
bool hasBrackets = line[4] == '<';
int codePointOffset = line.IndexOf(hasBrackets ? "> - " : "- ", 4);
if (codePointOffset < 0) throw new InvalidDataException();
codePointOffset += hasBrackets ? 4 : 2;
length = line.IndexOf(')', codePointOffset);
if (length < 0) throw new InvalidDataException();
length -= codePointOffset;
characterData.CrossRerefences.Add(int.Parse(line.Substring(codePointOffset, length), NumberStyles.HexNumber));
}
else throw new InvalidDataException();
}
continue;
}
if (line[0].IsHexDigit())
{
int codePoint = int.Parse(line.Substring(0, line.IndexOf('\t')), NumberStyles.HexNumber);
// This may return null, but for now, we will ignore code points that are not defined in UnicodeData.txt.
characterData = builder.GetUcd(codePoint);
// There should be no NamesList.txt entries for code points defined in a range.
if (characterData != null && !characterData.CodePointRange.IsSingleCodePoint)
{
// The only exception to this rule will be when we added the "Noncharacter_Code_Point" property to a few ranges, and we will ignore those.
if ((characterData.ContributoryProperties & ContributoryProperties.NonCharacterCodePoint) != 0)
characterData = null;
else
throw new InvalidDataException("Did not expect an NamesList.txt entry for U+" + codePoint.ToString("X4") + ".");
}
continue;
}
switch (line[0])
{
case '@':
case ';':
case '\t':
characterData = null;
break;
default:
throw new InvalidDataException("Unrecognized data in NamesList.txt.");
}
}
}
}
private static async Task ProcessBlocksFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(BlocksFileName).ConfigureAwait(false), ';'))
{
while (reader.MoveToNextLine())
{
builder.AddBlockEntry(new UnicodeBlock(UnicodeCharacterRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
builder.AddBlockEntry(new UnicodeBlock(UnicodeCodePointRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
}
}
}
@@ -327,5 +489,48 @@ namespace System.Unicode.Builder
}
}
}
private static async Task ProcessUnihanIrgSources(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
{
using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanIrgSourcesFileName).ConfigureAwait(false)))
{
while (reader.Read())
{
switch (reader.PropertyName)
{
case UnihanProperty.kRSUnicode:
var entry = builder.GetUnihan(reader.CodePoint);
var values = reader.PropertyValue.Split(' ');
foreach (var value in values)
{
bool isSimplified = false;
int index;
for (int i = 0; i < value.Length; ++i)
{
switch (value[i])
{
case '\'':
isSimplified = true;
goto case '.';
case '.':
index = i;
goto SeparatorFound;
}
}
throw new InvalidDataException("Failed to decode value for kRSUnicode / Unicode_Radical_Stroke.");
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;
default:
// Ignore unhandled properties for now.
break;
}
}
}
}
}
}
@@ -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<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
private readonly List<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
private readonly CjkRadicalData[] cjkRadicals = new CjkRadicalData[CjkRadicalCount];
public UnicodeInfoBuilder(Version unicodeVersion)
{
@@ -37,7 +40,7 @@ namespace System.Unicode.Builder
if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1;
} while (minIndex <= maxIndex);
} while (minIndex <= maxIndex);
return -1;
}
@@ -176,7 +179,7 @@ namespace System.Unicode.Builder
}
}
public void SetProperties(ContributoryProperties property, UnicodeCharacterRange codePointRange)
public void SetProperties(ContributoryProperties property, UnicodeCodePointRange codePointRange)
{
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
@@ -207,7 +210,7 @@ namespace System.Unicode.Builder
}
}
public void SetProperties(CoreProperties property, UnicodeCharacterRange codePointRange)
public void SetProperties(CoreProperties property, UnicodeCodePointRange codePointRange)
{
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
@@ -238,10 +241,24 @@ 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);
}
}
//public UnicodeInfo ToUnicodeData()
//{
@@ -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)
{
@@ -2,7 +2,7 @@
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8DFDEE6C-4F0D-4DE1-B346-574CB56D2B8B}</ProjectGuid>
<OutputType>Exe</OutputType>
@@ -52,7 +52,11 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyInfo.Common.cs">
<Link>Properties\AssemblyInfo.Common.cs</Link>
</Compile>
<Compile Include="BinaryWriterExtensions.cs" />
<Compile Include="CharExtensions.cs" />
<Compile Include="UnihanProperty.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
@@ -23,6 +23,8 @@ namespace System.Unicode.Builder
private string simplifiedVariant;
private string traditionalVariant;
private readonly List<UnicodeRadicalStrokeCount> unicodeRadicalStrokeCounts = new List<UnicodeRadicalStrokeCount>();
public int CodePoint { get { return codePoint; } }
public UnihanNumericType NumericType { get { return numericType; } set { numericType = value; } }
public long NumericValue { get { return numericValue; } set { numericValue = value; } }
@@ -36,6 +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 IList<UnicodeRadicalStrokeCount> UnicodeRadicalStrokeCounts { get { return unicodeRadicalStrokeCounts; } }
internal UnihanCharacterDataBuilder(int codePoint)
{
@@ -49,6 +52,7 @@ namespace System.Unicode.Builder
codePoint,
numericType,
numericValue,
unicodeRadicalStrokeCounts.ToArray(),
definition,
mandarinReading,
cantoneseReading,
@@ -67,6 +71,14 @@ namespace System.Unicode.Builder
UnihanFields fields = default(UnihanFields);
fields |= (UnihanFields)NumericType;
// For now, we have enough bits to encode the length of the array in the field specifier, so we'll do that.
// (NB: A quick analysis of the files revealed thare there are almost always exactly one Radical/Stroke count, and occasionally two, yet never more.)
if (unicodeRadicalStrokeCounts.Count > 0)
{
if (unicodeRadicalStrokeCounts.Count == 1) fields |= UnihanFields.UnicodeRadicalStrokeCount;
else if (unicodeRadicalStrokeCounts.Count == 2) fields |= UnihanFields.UnicodeRadicalStrokeCountTwice;
else fields |= UnihanFields.UnicodeRadicalStrokeCountMore;
}
if (Definition != null) fields |= UnihanFields.Definition;
if (MandarinReading != null) fields |= UnihanFields.MandarinReading;
if (CantoneseReading != null) fields |= UnihanFields.CantoneseReading;
@@ -82,6 +94,19 @@ namespace System.Unicode.Builder
writer.WriteCodePoint(UnihanCharacterData.PackCodePoint(codePoint));
if ((fields & UnihanFields.OtherNumeric) != 0) writer.Write(numericValue);
if ((fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0)
{
if ((fields & (UnihanFields.UnicodeRadicalStrokeCountMore)) == UnihanFields.UnicodeRadicalStrokeCountMore)
writer.Write(checked((byte)(unicodeRadicalStrokeCounts.Count - 3)));
foreach (var radicalStrokeCount in unicodeRadicalStrokeCounts)
{
writer.Write(radicalStrokeCount.Radical);
writer.Write((byte)(radicalStrokeCount.StrokeCount | (radicalStrokeCount.IsSimplified ? 0x80 : 0)));
}
}
if ((fields & UnihanFields.Definition) != 0) writer.Write(Definition);
if ((fields & UnihanFields.MandarinReading) != 0) writer.Write(MandarinReading);
if ((fields & UnihanFields.CantoneseReading) != 0) writer.Write(CantoneseReading);
@@ -22,7 +22,7 @@ namespace System.Unicode.Builder
public UnihanDataFileReader(Stream stream, bool leaveOpen)
{
reader = new UnicodeDataFileReader(stream, '\t', leaveOpen);
}
}
public void Dispose()
{
+5 -5
View File
@@ -16,7 +16,7 @@ namespace System.Unicode.Builder
byte[] buffer;
return new Utf8Buffer(bufferStack.TryPop(out buffer) ? buffer : new byte[100]);
}
}
private byte[] buffer;
private int length;
@@ -40,16 +40,16 @@ namespace System.Unicode.Builder
private void EnsureExtraCapacity(int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("requiredExtraCapacity");
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
if (buffer.Length < checked(length + count))
Array.Resize(ref buffer, Math.Max(length + count, buffer.Length << 1));
}
public void Append(byte[] value, int startIndex, int count)
{
if (value == null) throw new ArgumentNullException("value");
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException("startIndex");
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException("count");
if (value == null) throw new ArgumentNullException(nameof(value));
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException(nameof(startIndex));
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException(nameof(count));
EnsureExtraCapacity(value.Length);
+30
View File
@@ -0,0 +1,30 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace UnicodeInformation.Tests
{
public static class AssertEx
{
public static void ThrowsExactly<TException>(Action action, string methodName = null, string message = null)
where TException : Exception
{
try
{
action();
}
catch (TException ex)
{
if (ex.GetType() != typeof(TException))
Assert.Fail(message ?? (methodName != null ? "The " + methodName + " method should throw an exception of type " : "Expected an exception of type ") + typeof(TException).Name + " but got " + ex.GetType().Name + ".");
else
return;
}
Assert.Fail(message ?? (methodName != null ? "The " + methodName + " method should throw an exception of type " : "Expected an exception of type ") + typeof(TException).Name + ".");
}
}
}
@@ -1,36 +1,8 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Resources;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnicodeInformation.Tests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnicodeInformation.Tests")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: NeutralResourcesLanguage("en")]
[assembly: Guid("50337426-e884-4394-9e1a-f6f7a555f5d9")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
@@ -1,86 +0,0 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.IO.Compression;
using System.Unicode.Builder;
using System.Text;
namespace System.Unicode.Tests
{
[TestClass]
public class UnicodeDataManagerTests
{
private const string UcdDirectoryName = "UCD";
[TestInitialize]
public void Initialize()
{
var directoryName = Path.GetFullPath(UcdDirectoryName);
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
string ucdFileName = Path.Combine(directoryName, "UCD.zip");
string unihanFileName = Path.Combine(directoryName, "Unihan.zip");
if (!File.Exists(ucdFileName))
{
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/UCD.zip", ucdFileName);
ZipFile.ExtractToDirectory(ucdFileName, directoryName);
}
if (!File.Exists(unihanFileName))
{
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/Unihan.zip", unihanFileName);
ZipFile.ExtractToDirectory(unihanFileName, directoryName);
}
}
}
[TestMethod]
public async Task BuildDataAsync()
{
var source = new FileDataSource(UcdDirectoryName);
var data = (await UnicodeDataProcessor.BuildDataAsync(source, source));
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
}
[TestMethod]
public async Task BuildAndWriteDataAsync()
{
var source = new FileDataSource(UcdDirectoryName);
var data = await UnicodeDataProcessor.BuildDataAsync(source, source);
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
{
data.WriteToStream(stream);
}
}
#if DEBUG
[TestMethod]
public void TestCodePointEncoding()
{
using (var stream = new MemoryStream(4))
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
{
for (int i = 0; i <= 0x10FFFF; ++i)
{
writer.WriteCodePoint(i);
writer.Flush();
stream.Position = 0;
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
stream.Position = 0;
}
}
}
#endif
}
}
@@ -0,0 +1,179 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using System.IO.Compression;
using System.Unicode.Builder;
using System.Text;
using System.Net.Http;
using System.Collections.Generic;
namespace System.Unicode.Tests
{
[TestClass]
public class UnicodeInfoBuilderTests
{
private sealed class FileHttpResponseHandler : HttpMessageHandler
{
private readonly Dictionary<Uri, string> registeredFiles = new Dictionary<Uri, string>();
public void RegisterFile(Uri uri, string fileName)
{
registeredFiles.Add(uri, fileName);
}
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
string fileName;
if (registeredFiles.TryGetValue(request.RequestUri, out fileName))
{
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(await Task.Run(() => File.ReadAllBytes(fileName)).ConfigureAwait(false)) };
}
else
{
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
}
}
}
private const string HttpCacheDirectory = "_HttpCache";
private static async Task RegisterAndDownloadFile(FileHttpResponseHandler handler, string httpCacheDirectory, Uri baseUri, string fileName)
{
var uri = new Uri(baseUri, fileName);
string path = Path.Combine(httpCacheDirectory, fileName);
if (!File.Exists(path))
{
using (var httpClient = new HttpClient())
{
var data = await httpClient.GetByteArrayAsync(uri).ConfigureAwait(false);
File.WriteAllBytes(path, data);
}
}
handler.RegisterFile(uri, path);
}
[TestInitialize]
public void Initialize()
{
var httpCacheDirectory = Path.GetFullPath(HttpCacheDirectory);
if (!Directory.Exists(httpCacheDirectory)) Directory.CreateDirectory(httpCacheDirectory);
var handler = new FileHttpResponseHandler();
var ucdTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UcdArchiveName);
var unihanTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UnihanArchiveName);
Program.HttpMessageHandler = handler;
if (Directory.Exists(Program.UcdDirectoryName)) Directory.Delete(Program.UcdDirectoryName, true);
if (File.Exists(Program.UcdArchiveName)) File.Delete(Program.UcdArchiveName);
if (Directory.Exists(Program.UnihanDirectoryName)) Directory.Delete(Program.UnihanDirectoryName, true);
if (File.Exists(Program.UnihanArchiveName)) File.Delete(Program.UnihanArchiveName);
Task.WaitAll(ucdTask, unihanTask);
}
[TestMethod]
public void DownloadUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, false, false))
{
}
}
[TestMethod]
public void DownloadAndSaveUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, false))
{
}
}
[TestMethod]
public void ExtractUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, true))
{
}
}
[TestMethod]
public void DownloadUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, false, false))
{
}
}
[TestMethod]
public void DownloadAndSaveUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, false))
{
}
}
[TestMethod]
public void ExtractUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, true))
{
}
}
[TestMethod]
public async Task BuildDataAsync()
{
using (var ucdSource = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var unihanSource = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
{
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
}
}
[TestMethod]
public async Task BuildAndWriteDataAsync()
{
using (var ucdSource = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var unihanSource = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
{
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
//using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
using (var stream = File.Create("ucd.dat"))
{
data.WriteToStream(stream);
}
}
}
#if DEBUG
[TestMethod]
public void CodePointEncodingTest()
{
using (var stream = new MemoryStream(4))
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
{
for (int i = 0; i <= 0x10FFFF; ++i)
{
writer.WriteCodePoint(i);
writer.Flush();
stream.Position = 0;
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
stream.Position = 0;
}
}
}
#endif
}
}
@@ -0,0 +1,300 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Unicode;
using System.Globalization;
using System.Collections.Generic;
using System.Collections;
namespace UnicodeInformation.Tests
{
[TestClass]
public class UnicodeInfoTests
{
[TestMethod]
public void CodePointEnumeratorTest()
{
string text = "\u0041\U0001F600\u00E9";
var enumerable = text.AsCodePointEnumerable();
Assert.AreEqual(text, enumerable.Text);
var enumerator = enumerable.GetEnumerator();
Assert.AreEqual(true, enumerator.MoveNext());
Assert.AreEqual(0x0041, enumerator.Current);
Assert.AreEqual(true, enumerator.MoveNext());
Assert.AreEqual(0x1F600, enumerator.Current);
Assert.AreEqual(true, enumerator.MoveNext());
Assert.AreEqual(0x00E9, enumerator.Current);
Assert.AreEqual(false, enumerator.MoveNext());
var genericEnumerator = ((IEnumerable<int>)enumerable).GetEnumerator();
Assert.AreEqual(true, genericEnumerator.MoveNext());
Assert.AreEqual(0x0041, genericEnumerator.Current);
Assert.AreEqual(true, genericEnumerator.MoveNext());
Assert.AreEqual(0x1F600, genericEnumerator.Current);
Assert.AreEqual(true, genericEnumerator.MoveNext());
Assert.AreEqual(0x00E9, genericEnumerator.Current);
Assert.AreEqual(false, genericEnumerator.MoveNext());
var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator();
Assert.AreEqual(true, legacyEnumerator.MoveNext());
Assert.AreEqual(0x0041, legacyEnumerator.Current);
Assert.AreEqual(true, legacyEnumerator.MoveNext());
Assert.AreEqual(0x1F600, legacyEnumerator.Current);
Assert.AreEqual(true, legacyEnumerator.MoveNext());
Assert.AreEqual(0x00E9, legacyEnumerator.Current);
Assert.AreEqual(false, legacyEnumerator.MoveNext());
}
[TestMethod]
public void DisplayTextTest()
{
for (int i = 0; i <= 0x20; ++i)
{
Assert.AreEqual(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(i));
Assert.AreEqual(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(UnicodeInfo.GetCharInfo(i)));
}
Assert.AreEqual("\u0041", UnicodeInfo.GetDisplayText(0x0041));
Assert.AreEqual("\U0001F600", UnicodeInfo.GetDisplayText(0x1F600));
Assert.AreEqual("\u00E9", UnicodeInfo.GetDisplayText(0x00E9));
}
private static void AssertChar(int codePoint, UnicodeCategory category, string name, string block)
{
AssertChar(codePoint, category, UnicodeNumericType.None, null, name, block);
}
private static void AssertChar(int codePoint, UnicodeCategory category, UnicodeNumericType numericType, UnicodeRationalNumber? numericValue, string name, string block)
{
var info = UnicodeInfo.GetCharInfo(codePoint);
Assert.AreEqual(codePoint, info.CodePoint);
Assert.AreEqual(category, info.Category);
Assert.AreEqual(numericType, info.NumericType);
Assert.AreEqual(numericValue, info.NumericValue);
Assert.AreEqual(name, info.Name);
Assert.AreEqual(block, UnicodeInfo.GetBlockName(codePoint));
Assert.AreEqual(block, info.Block);
}
[TestMethod]
public void CharacterInfoTest()
{
AssertChar(0x0030, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(0), "DIGIT ZERO", "Basic Latin");
AssertChar(0x0031, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(1), "DIGIT ONE", "Basic Latin");
AssertChar(0x0032, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(2), "DIGIT TWO", "Basic Latin");
AssertChar(0x0035, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(5), "DIGIT FIVE", "Basic Latin");
AssertChar(0x0039, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, new UnicodeRationalNumber(9), "DIGIT NINE", "Basic Latin");
AssertChar(0x0041, UnicodeCategory.UppercaseLetter, "LATIN CAPITAL LETTER A", "Basic Latin");
AssertChar(0x1F600, UnicodeCategory.OtherSymbol, "GRINNING FACE", "Emoticons");
AssertChar(0x00E9, UnicodeCategory.LowercaseLetter, "LATIN SMALL LETTER E WITH ACUTE", "Latin-1 Supplement");
AssertChar(0xD4DB, UnicodeCategory.OtherLetter, "HANGUL SYLLABLE PWILH", "Hangul Syllables");
AssertChar(0x1F574, UnicodeCategory.OtherSymbol, "MAN IN BUSINESS SUIT LEVITATING", "Miscellaneous Symbols and Pictographs");
}
[TestMethod]
public void RationalNumberTest()
{
Assert.AreEqual(true, default(UnicodeRationalNumber).IsDefaultValue);
Assert.AreEqual("1", new UnicodeRationalNumber(1).ToString());
Assert.AreEqual("1", new UnicodeRationalNumber(1, 1).ToString());
Assert.AreEqual(new UnicodeRationalNumber(1), new UnicodeRationalNumber(1, 1));
Assert.AreEqual("1/100", new UnicodeRationalNumber(1, 100).ToString());
Assert.AreEqual("-20/7", new UnicodeRationalNumber(-20, 7).ToString());
Assert.AreEqual("-5", new UnicodeRationalNumber(-5).ToString());
Assert.AreEqual(long.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue).ToString());
Assert.AreEqual(long.MaxValue.ToString() + "/" + byte.MaxValue.ToString(), new UnicodeRationalNumber(long.MaxValue, byte.MaxValue).ToString());
Assert.AreEqual(string.Empty, default(UnicodeRationalNumber).ToString());
Assert.AreEqual(new UnicodeRationalNumber(0), UnicodeRationalNumber.Parse("0"));
Assert.AreEqual(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1"));
Assert.AreEqual(new UnicodeRationalNumber(1), UnicodeRationalNumber.Parse("1/1"));
Assert.AreEqual(new UnicodeRationalNumber(1, 10), UnicodeRationalNumber.Parse("1/10"));
Assert.AreNotEqual(new UnicodeRationalNumber(2, 10), UnicodeRationalNumber.Parse("1/10"));
Assert.AreNotEqual(new UnicodeRationalNumber(1, 20), UnicodeRationalNumber.Parse("1/10"));
Assert.AreNotEqual(new UnicodeRationalNumber(2, 2), new UnicodeRationalNumber(1, 1));
AssertEx.ThrowsExactly<ArgumentNullException>(() => UnicodeRationalNumber.Parse(null), "UnicodeRationalNumber.Parse");
AssertEx.ThrowsExactly<ArgumentException>(() => UnicodeRationalNumber.Parse(string.Empty), "UnicodeRationalNumber.Parse");
var numbers = new[]
{
default(UnicodeRationalNumber),
new UnicodeRationalNumber(0),
new UnicodeRationalNumber(1),
new UnicodeRationalNumber(1, 10),
new UnicodeRationalNumber(1, 100),
new UnicodeRationalNumber(10),
new UnicodeRationalNumber(100),
new UnicodeRationalNumber(1000),
new UnicodeRationalNumber(1000000),
new UnicodeRationalNumber(1000000000),
new UnicodeRationalNumber(1000000000000),
};
var hashSet = new HashSet<UnicodeRationalNumber>();
// Verify that all numbers are unique
foreach (var number in numbers)
Assert.AreEqual(true, hashSet.Add(number));
// Verify that all numbers are already in the list
foreach (var number in numbers)
Assert.AreEqual(false, hashSet.Add(number));
}
[TestMethod]
public void HangulNameTest()
{
#if DEBUG
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\0'));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\uABFF'));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName('\uD7A5'));
#endif
Assert.AreEqual("HANGUL SYLLABLE PWILH", UnicodeInfo.GetName(0xD4DB));
Assert.AreEqual("HANGUL SYLLABLE PWAENG", UnicodeInfo.GetName(0xD439));
Assert.AreEqual("HANGUL SYLLABLE PANJ", UnicodeInfo.GetName(0xD311));
Assert.AreEqual("HANGUL SYLLABLE TOLM", UnicodeInfo.GetName(0xD1AA));
}
[TestMethod]
public void BlockNameTest()
{
Assert.AreEqual("Basic Latin", UnicodeInfo.GetBlockName(0x0041));
Assert.AreEqual("Miscellaneous Technical", UnicodeInfo.GetBlockName(0x2307));
Assert.AreEqual("Hangul Syllables", UnicodeInfo.GetBlockName(0xD311));
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(1, radical1.RadicalIndex);
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(214, radical214.RadicalIndex);
Assert.AreEqual('\u2FD5', radical214.TraditionalRadicalCodePoint);
Assert.AreEqual('\u9FA0', radical214.TraditionalCharacterCodePoint);
Assert.AreEqual('\u2FD5', radical214.SimplifiedRadicalCodePoint);
Assert.AreEqual('\u9FA0', radical214.SimplifiedCharacterCodePoint);
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(0), nameof(UnicodeInfo.GetCjkRadicalInfo));
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(215), nameof(UnicodeInfo.GetCjkRadicalInfo));
}
[TestMethod]
public void CodePointRangeTest()
{
var fullRange = new UnicodeCodePointRange(0, 0x10FFFF);
Assert.AreEqual(0, fullRange.FirstCodePoint);
Assert.AreEqual(0x10FFFF, fullRange.LastCodePoint);
Assert.AreEqual(false, fullRange.IsSingleCodePoint);
var letterA = new UnicodeCodePointRange('A');
Assert.AreEqual('A', letterA.FirstCodePoint);
Assert.AreEqual('A', letterA.LastCodePoint);
Assert.AreEqual(true, letterA.IsSingleCodePoint);
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(0x110000));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(int.MaxValue));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1, 10));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(10, 0x110000));
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(-1, 0x110000));
}
[TestMethod]
public void CodePointRangeEnumerationTest()
{
const int start = 0xA3F;
const int end = 0x105F;
// Generic test
{
int i = start;
foreach (int n in new UnicodeCodePointRange(start, end))
{
Assert.AreEqual(i++, n);
}
}
// Nongeneric test
{
int i = start;
var enumerator = (IEnumerator)new UnicodeCodePointRange(start, end).GetEnumerator();
while (enumerator.MoveNext())
{
Assert.AreEqual(i++, enumerator.Current);
}
enumerator.Reset();
Assert.AreEqual(true, enumerator.MoveNext());
Assert.AreEqual(start, enumerator.Current);
}
}
#if DEBUG
[TestMethod]
public void UnihanCodePointPackingTest()
{
for (int i = 0x3400; i < 0x4E00; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x4E00; i < 0xA000; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0xF900; i < 0xFB00; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x20000; i < 0x2F800; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x2F800; i < 0x30000; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
const string packCodePointErrorMessage = "The PackCodePoint method should fail for code points outside of the valid range.";
const string unpackCodePointErrorMessage = "The PackCodePoint method should fail for values outside of the valid range.";
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xA000), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xFB00), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0x30000), nameof(UnihanCharacterData.PackCodePoint), packCodePointErrorMessage);
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(-1), nameof(UnihanCharacterData.UnpackCodePoint), unpackCodePointErrorMessage);
AssertEx.ThrowsExactly<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(0x20000), nameof(UnihanCharacterData.UnpackCodePoint), unpackCodePointErrorMessage);
}
#endif
}
}
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{50337426-E884-4394-9E1A-F6F7A555F5D9}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -60,8 +60,13 @@
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="UnicodeDataManagerTests.cs" />
<Compile Include="..\AssemblyInfo.Common.cs">
<Link>Properties\AssemblyInfo.Common.cs</Link>
</Compile>
<Compile Include="AssertEx.cs" />
<Compile Include="UnicodeInfoBuilderTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UnicodeInfoTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UnicodeInformation.Builder\UnicodeInformation.Builder.csproj">
+6
View File
@@ -13,12 +13,18 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeInformation.Builder"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{73097DF3-04B7-4C5F-B4EA-0EB800E40702}"
ProjectSection(SolutionItems) = preProject
AssemblyInfo.Common.cs = AssemblyInfo.Common.cs
Example.cs = Example.cs
LICENSE.txt = LICENSE.txt
README.md = README.md
System.Unicode.snk = System.Unicode.snk
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{311FC325-8547-4806-8617-956F1356A92C}"
ProjectSection(SolutionItems) = preProject
docs\uci-00.png = docs\uci-00.png
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+1 -1
View File
@@ -26,7 +26,7 @@ namespace System.Unicode
[ValueName("CS"), ValueName("Common_Separator"), Display(Name = "Common_Separator", Description = "commas, colons, and slashes")]
CommonSeparator,
[ValueName("NSM"), ValueName("Nonspacing_Mark"), Display(Name = "Nonspacing_Mark", Description = "any nonspacing mark")]
NonspacingMark,
NonSpacingMark,
[ValueName("BN"), ValueName("Boundary_Neutral"), Display(Name = "Boundary_Neutral", Description = "most format characters, control codes, or noncharacters")]
BoundaryNeutral,
[ValueName("B"), ValueName("Paragraph_Separator"), Display(Name = "Paragraph_Separator", Description = "various newline characters")]
+28
View File
@@ -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; } }
}
}
+29
View File
@@ -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;
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ namespace System.Unicode
public CodePointEnumerator(string text)
{
if (text == null) throw new ArgumentNullException("text");
if (text == null) throw new ArgumentNullException(nameof(text));
this.text = text;
this.current = 0;
@@ -10,7 +10,7 @@ namespace System.Unicode
public enum CompatibilityFormattingTag : byte
{
Canonical = 0,
[ValueName("font"), Display(Name = "font", Description = "Font variant (for example, a blackletter form)")]
[ValueName("font"), Display(Name = "font", Description = "Font variant (for example, a blackletter form)")]
Font,
[ValueName("noBreak"), Display(Name = "noBreak", Description = "No-break version of a space or hyphen")]
NoBreak,
+1 -1
View File
@@ -26,7 +26,7 @@ namespace System.Unicode
where attr.Name != null
select new KeyValuePair<string, T>(attr.Name, (T)field.GetValue(null))
).ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
}
}
public static bool TryGetNamedValue(string name, out T value)
{
+61
View File
@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
internal static class HangulInfo
{
// Constants defined on page 144 of the Unicode 7.0 Standard (3.12)
private const ushort SBase = 0xAC00;
private const ushort LBase = 0x1100;
private const ushort VBase = 0x1161;
private const ushort TBase = 0x11A7;
private const int LCount = 19;
private const int VCount = 21;
private const int TCount = 28;
private const int NCount = VCount * TCount;
private const int SCount = LCount * NCount;
private static readonly string[] JamoLTable =
{
"G", "GG", "N", "D", "DD", "R", "M", "B", "BB",
"S", "SS", "", "J", "JJ", "C", "K", "T", "P", "H"
};
private static readonly string[] JamoVTable =
{
"A", "AE", "YA", "YAE", "EO", "E", "YEO", "YE", "O",
"WA", "WAE", "OE", "YO", "U", "WEO", "WE", "WI",
"YU", "EU", "YI", "I"
};
private static readonly string[] JamoTTable =
{
"", "G", "GG", "GS", "N", "NJ", "NH", "D", "L", "LG", "LM",
"LB", "LS", "LT", "LP", "LH", "M", "B", "BS",
"S", "SS", "NG", "J", "C", "K", "T", "P", "H"
};
// Algorithm defined on page 150 of the Unicode 7.0 Standard (3.12)
internal static string GetHangulName(char codePoint)
{
int sIndex = codePoint - SBase;
if (sIndex < 0 || sIndex >= SCount) throw new ArgumentOutOfRangeException(nameof(codePoint));
int lIndex = sIndex / NCount;
int vIndex = (sIndex % NCount) / TCount;
int tIndex = sIndex % TCount;
return "HANGUL SYLLABLE " + JamoLTable[lIndex] + JamoVTable[vIndex] + JamoTTable[tIndex];
}
internal static bool IsHangul(int codePoint)
{
return codePoint >= SBase && codePoint <= SBase + SCount;
}
}
}
+4 -27
View File
@@ -1,34 +1,11 @@
using System.Resources;
using System.Reflection;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("UnicodeInformation")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("UnicodeInformation")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyTitle(".NET Unicode Information Library")]
[assembly: AssemblyDescription("Library providing access to Unicode data to .NET clients.")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: InternalsVisibleTo("UnicodeInformation.Builder, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
#if DEBUG
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
#endif
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+6 -4
View File
@@ -12,9 +12,9 @@ namespace System.Unicode
internal enum UcdFields : ushort
{
// Not really a field, just here to indicate that the entry is a range
CodePointRange = 1,
Name = 2,
CodePointRange = 1,
Name = 2, // Will stand in for official name as well as related names.
Category = 4,
CanonicalCombiningClass = 8,
BidirectionalClass = 16,
@@ -23,7 +23,7 @@ namespace System.Unicode
// NumericType / NumericValue : Not exactly a bit mask here… More like [0…3] << 6
NumericDecimal = 64,
NumericDigit = 128,
NumericNumeric = 192,
NumericNumeric = 192,
// This is a yes/no field, so obviously, no extra storage is required for this one…
BidirectionalMirrored = 256,
@@ -35,5 +35,7 @@ namespace System.Unicode
ContributoryProperties = 8192,
CoreProperties = 16384,
CrossRerefences = 32768,
}
}
+3 -3
View File
@@ -8,13 +8,13 @@ namespace System.Unicode
{
public struct UnicodeBlock
{
public readonly UnicodeCharacterRange CodePointRange;
public readonly UnicodeCodePointRange CodePointRange;
public readonly string Name;
internal UnicodeBlock(UnicodeCharacterRange codePointRange, string name)
internal UnicodeBlock(UnicodeCodePointRange codePointRange, string name)
{
this.CodePointRange = codePointRange;
this.Name = name;
}
}
}
}
+3 -3
View File
@@ -50,10 +50,10 @@ namespace System.Unicode
{
var dictionary = new Dictionary<string, UnicodeCategory>(StringComparer.OrdinalIgnoreCase);
foreach (var info in categories)
foreach (var info in categories)
{
dictionary.Add(info.ShortName, info.Category);
}
}
return dictionary;
}
@@ -83,7 +83,7 @@ namespace System.Unicode
public static UnicodeCategoryInfo Get(UnicodeCategory category)
{
return categories[(int)category];
}
}
public static UnicodeCategoryInfo FromShortName(string name)
{
+47 -24
View File
@@ -10,54 +10,77 @@ namespace System.Unicode
public struct UnicodeCharInfo
{
private readonly int codePoint;
private readonly string name;
private readonly UnicodeCharacterData unicodeCharacterData;
private readonly UnihanCharacterData unihanCharacterData;
private readonly string block;
public int CodePoint { get { return codePoint; } }
public string Name
{
get
{
return unicodeCharacterData.Name == null || unicodeCharacterData.CodePointRange.IsSingleCodePoint ?
unicodeCharacterData.Name :
unicodeCharacterData.Name + "-" + codePoint.ToString("X4");
}
}
[ValueName("Name"), ValueName("na")]
public string Name { get { return name; } }
[ValueName("Name_Alias")]
public UnicodeNameAliasCollection NameAliases { get { return new UnicodeNameAliasCollection(unicodeCharacterData?.NameAliases); } }
public UnicodeCategory Category { get { return unicodeCharacterData != null ? unicodeCharacterData.Category : UnicodeCategory.OtherNotAssigned; } }
public string Block { get { return block ?? "No_Block"; } }
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData.CanonicalCombiningClass; } }
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData.BidirectionalClass; } }
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData.DecompositionType; } }
public string DecompositionMapping { get { return unicodeCharacterData.DecompositionMapping; } }
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData.NumericType; } }
[ValueName("General_Category"), ValueName("gc")]
public UnicodeCategory Category { get { return unicodeCharacterData?.Category ?? UnicodeCategory.OtherNotAssigned; } }
[ValueName("Block"), ValueName("blk")]
public string Block { get { return block ?? UnicodeInfo.DefaultBlock; } }
[ValueName("Canonical_Combining_Class"), ValueName("ccc")]
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData?.CanonicalCombiningClass ?? CanonicalCombiningClass.NotReordered; } }
[ValueName("Bidi_Class"), ValueName("bc")]
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData?.BidirectionalClass ?? BidirectionalClass.LeftToRight; } }
[ValueName("Decomposition_Type"), ValueName("dt")]
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData?.DecompositionType ?? CompatibilityFormattingTag.Canonical; } }
[ValueName("Decomposition_Mapping"), ValueName("dm")]
public string DecompositionMapping { get { return unicodeCharacterData?.DecompositionMapping; } }
[ValueName("Numeric_Type"), ValueName("nt")]
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData?.NumericType ?? UnicodeNumericType.None; } }
public UnihanNumericType UnihanNumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType : UnihanNumericType.None; } }
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData.NumericValue; } }
public bool BidirectionalMirrored { get { return unicodeCharacterData.BidirectionalMirrored; } }
public string OldName { get { return unicodeCharacterData.OldName; } }
public string SimpleUpperCaseMapping { get { return unicodeCharacterData.SimpleUpperCaseMapping; } }
public string SimpleLowerCaseMapping { get { return unicodeCharacterData.SimpleLowerCaseMapping; } }
public string SimpleTitleCaseMapping { get { return unicodeCharacterData.SimpleTitleCaseMapping; } }
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData.ContributoryProperties; } }
public CoreProperties CoreProperties { get { return unicodeCharacterData.CoreProperties; } }
[ValueName("Numeric_Value"), ValueName("nv")]
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData?.NumericValue; } }
[ValueName("Bidi_Mirrored")]
public bool BidirectionalMirrored { get { return unicodeCharacterData?.BidirectionalMirrored ?? false; } }
[ValueName("Unicode_1_Name"), ValueName("na1")]
public string OldName { get { return unicodeCharacterData?.OldName; } }
[ValueName("Simple_Uppercase_Mapping"), ValueName("suc")]
public string SimpleUpperCaseMapping { get { return unicodeCharacterData?.SimpleUpperCaseMapping; } }
[ValueName("Simple_Lowercase_Mapping"), ValueName("slc")]
public string SimpleLowerCaseMapping { get { return unicodeCharacterData?.SimpleLowerCaseMapping; } }
[ValueName("Simple_Titlecase_Mapping"), ValueName("stc")]
public string SimpleTitleCaseMapping { get { return unicodeCharacterData?.SimpleTitleCaseMapping; } }
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData?.ContributoryProperties ?? 0; } }
public CoreProperties CoreProperties { get { return unicodeCharacterData?.CoreProperties ?? 0; } }
public UnicodeCrossReferenceCollection CrossRerefences { get { return new UnicodeCrossReferenceCollection(unicodeCharacterData?.CrossRerefences); } }
[ValueName("kRSUnicode"), ValueName("cjkRSUnicode"), ValueName("Unicode_Radical_Stroke"), ValueName("URS")]
public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts { get { return new UnicodeRadicalStrokeCountCollection(unihanCharacterData?.UnicodeRadicalStrokeCounts); } }
[ValueName("kDefinition")]
public string Definition { get { return unihanCharacterData?.Definition; } }
[ValueName("kMandarin")]
public string MandarinReading { get { return unihanCharacterData?.MandarinReading; } }
[ValueName("kCantonese")]
public string CantoneseReading { get { return unihanCharacterData?.CantoneseReading; } }
[ValueName("kJapaneseKun")]
public string JapaneseKunReading { get { return unihanCharacterData?.JapaneseKunReading; } }
[ValueName("kJapaneseOn")]
public string JapaneseOnReading { get { return unihanCharacterData?.JapaneseOnReading; } }
[ValueName("kKorean")]
public string KoreanReading { get { return unihanCharacterData?.KoreanReading; } }
[ValueName("kHangul")]
public string HangulReading { get { return unihanCharacterData?.HangulReading; } }
[ValueName("kVietnamese")]
public string VietnameseReading { get { return unihanCharacterData?.VietnameseReading; } }
[ValueName("kSimplifiedVariant")]
public string SimplifiedVariant { get { return unihanCharacterData?.SimplifiedVariant; } }
[ValueName("kTraditionalVariant")]
public string TraditionalVariant { get { return unihanCharacterData?.TraditionalVariant; } }
internal UnicodeCharInfo(int codePoint, UnicodeCharacterData unicodeCharacterData, UnihanCharacterData unihanCharacterData, string block)
{
this.codePoint = codePoint;
this.name = UnicodeInfo.GetName(codePoint, unicodeCharacterData);
this.unicodeCharacterData = unicodeCharacterData;
this.unihanCharacterData = unihanCharacterData;
this.block = block;
+11 -8
View File
@@ -9,8 +9,9 @@ namespace System.Unicode
{
internal sealed class UnicodeCharacterData
{
public readonly UnicodeCharacterRange CodePointRange;
public readonly UnicodeCodePointRange CodePointRange;
public readonly string Name;
public readonly UnicodeNameAlias[] NameAliases;
public readonly UnicodeCategory Category;
public readonly CanonicalCombiningClass CanonicalCombiningClass;
public readonly BidirectionalClass BidirectionalClass;
@@ -26,31 +27,33 @@ namespace System.Unicode
public readonly ContributoryProperties ContributoryProperties;
public readonly CoreProperties CoreProperties;
public readonly int[] RelatedCodePoints; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
internal UnicodeCharacterData
(
UnicodeCharacterRange codePointRange,
UnicodeCodePointRange codePointRange,
string name,
UnicodeNameAlias[] nameAliases,
UnicodeCategory category,
CanonicalCombiningClass canonicalCombiningClass,
BidirectionalClass bidirectionalClass,
CompatibilityFormattingTag decompositionType,
string decompositionMapping,
string decompositionMapping,
UnicodeNumericType numericType,
UnicodeRationalNumber numericValue,
bool bidirectionalMirrored,
string oldName,
string simpleUpperCaseMapping,
string simpleUpperCaseMapping,
string simpleLowerCaseMapping,
string simpleTitleCaseMapping,
ContributoryProperties contributoryProperties,
CoreProperties coreProperties,
int[] relatedCodePoints
int[] crossRerefences
)
{
this.CodePointRange = codePointRange;
this.Name = name;
this.NameAliases = nameAliases;
this.Category = category;
this.CanonicalCombiningClass = canonicalCombiningClass;
this.BidirectionalClass = bidirectionalClass;
@@ -65,8 +68,8 @@ namespace System.Unicode
this.SimpleTitleCaseMapping = simpleTitleCaseMapping;
this.ContributoryProperties = contributoryProperties;
this.CoreProperties = coreProperties;
this.RelatedCodePoints = relatedCodePoints;
}
this.CrossRerefences = crossRerefences;
}
public UnicodeRationalNumber? NumericValue { get { return NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?; } }
}
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace System.Unicode
{
public struct UnicodeCharacterRange : IEnumerable<int>
public struct UnicodeCodePointRange : IEnumerable<int>
{
public struct Enumerator : IEnumerator<int>
{
@@ -39,20 +39,20 @@ namespace System.Unicode
public bool IsSingleCodePoint { get { return FirstCodePoint == LastCodePoint; } }
public UnicodeCharacterRange(int codePoint)
public UnicodeCodePointRange(int codePoint)
{
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("codePoint");
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(codePoint));
FirstCodePoint = codePoint;
LastCodePoint = codePoint;
}
public UnicodeCharacterRange(int firstCodePoint, int lastCodePoint)
public UnicodeCodePointRange(int firstCodePoint, int lastCodePoint)
{
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("firstCodePoint");
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("lastCodePoint");
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(firstCodePoint));
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(lastCodePoint));
FirstCodePoint = firstCodePoint;
FirstCodePoint = firstCodePoint;
LastCodePoint = lastCodePoint;
}
@@ -71,7 +71,7 @@ namespace System.Unicode
return FirstCodePoint == LastCodePoint ? FirstCodePoint.ToString("X4") : FirstCodePoint.ToString("X4") + ".." + LastCodePoint.ToString("X4");
}
public static UnicodeCharacterRange Parse(string s)
public static UnicodeCodePointRange Parse(string s)
{
int start, end;
@@ -86,9 +86,9 @@ namespace System.Unicode
{
start = int.Parse(s.Substring(0, rangeSeparatorOffset), NumberStyles.HexNumber);
end = int.Parse(s.Substring(rangeSeparatorOffset + 2), NumberStyles.HexNumber);
}
}
return new UnicodeCharacterRange(start, end);
return new UnicodeCodePointRange(start, end);
}
public Enumerator GetEnumerator() { return new Enumerator(FirstCodePoint, LastCodePoint); }
@@ -0,0 +1,70 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
public struct UnicodeCrossReferenceCollection : IList<int>
{
private static int[] EmptyArray = new int[0];
public struct Enumerator : IEnumerator<int>
{
private readonly int[] items;
private int index;
internal Enumerator(int[] items)
{
this.items = items;
this.index = -1;
}
public void Dispose() { }
public int Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
private readonly int[] items;
public UnicodeCrossReferenceCollection() { items = EmptyArray; }
internal UnicodeCrossReferenceCollection(int[] items) { this.items = items ?? EmptyArray; }
public int this[int index] { get { return items[index]; } }
int IList<int>.this[int index]
{
get { return items[index]; }
set { throw new NotSupportedException(); }
}
public int Count { get { return items.Length; } }
bool ICollection<int>.IsReadOnly { get { return true; } }
public void Add(int item) { throw new NotSupportedException(); }
public void Insert(int index, int item) { throw new NotSupportedException(); }
public bool Remove(int item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
public int IndexOf(int item) { return Array.IndexOf(items, item); }
public bool Contains(int item) { return IndexOf(item) >= 0; }
public void CopyTo(int[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
}
+214 -25
View File
@@ -12,23 +12,29 @@ namespace System.Unicode
{
public static class UnicodeInfo
{
public const string DefaultBlock = "No_Block";
private static readonly Version unicodeVersion;
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);
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)
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))
{
int i;
if (reader.ReadByte() != 'U'
| reader.ReadByte() != 'C'
| reader.ReadByte() != 'D')
@@ -41,22 +47,43 @@ namespace System.Unicode
var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte());
var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)];
byte[] nameBuffer = new byte[128];
int mci = 0;
for (int i = 0; i < unicodeCharacterDataEntries.Length; ++i)
for (i = 0; i < unicodeCharacterDataEntries.Length; ++i)
{
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader);
if ((unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer)).CodePointRange.Contains(i)) mci = i;
else
{
++i;
break;
}
}
maxContiguousIndex = mci;
for (; i < unicodeCharacterDataEntries.Length; ++i)
{
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer);
}
var blockEntries = new UnicodeBlock[reader.ReadByte()];
for (int i = 0; i < blockEntries.Length; ++i)
for (i = 0; i < blockEntries.Length; ++i)
{
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 (int i = 0; i < unihanCharacterDataEntries.Length; ++i)
for (i = 0; i < unihanCharacterDataEntries.Length; ++i)
{
unihanCharacterDataEntries[i] = ReadUnihanCharacterDataEntry(reader);
}
@@ -64,17 +91,52 @@ namespace System.Unicode
unicodeVersion = fileUnicodeVersion;
unicodeCharacterData = unicodeCharacterDataEntries;
unihanCharacterData = unihanCharacterDataEntries;
radicals = cjkRadicalEntries;
blocks = blockEntries;
}
}
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader)
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer)
{
var fields = (UcdFields)reader.ReadUInt16();
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCharacterRange(ReadCodePoint(reader));
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCodePointRange(ReadCodePoint(reader));
string name = null;
UnicodeNameAlias[] nameAliases = UnicodeNameAlias.EmptyArray;
// Read all the official names of the character.
if ((fields & UcdFields.Name) != 0)
{
int length = reader.ReadByte();
byte @case = (byte)(length & 0xC0);
if (@case < 0x80) // Handles the case where only the name is present.
{
length = (length & 0x7F) + 1;
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
}
else
{
nameAliases = new UnicodeNameAlias[(length & 0x3F) + 1];
if ((@case & 0x40) != 0)
{
length = reader.ReadByte() + 1;
if (length > 128) throw new InvalidDataException("Did not expect names longer than 128 bytes.");
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
}
for (int i = 0; i < nameAliases.Length; ++i)
{
nameAliases[i] = new UnicodeNameAlias(reader.ReadString(), (UnicodeNameAliasKind)(reader.ReadByte()));
}
}
}
string name = (fields & UcdFields.Name) != 0 ? reader.ReadString() : null;
var category = (fields & UcdFields.Category) != 0 ? (UnicodeCategory)reader.ReadByte() : UnicodeCategory.OtherNotAssigned;
var canonicalCombiningClass = (fields & UcdFields.CanonicalCombiningClass) != 0 ? (CanonicalCombiningClass)reader.ReadByte() : CanonicalCombiningClass.NotReordered;
var bidirectionalClass = (fields & UcdFields.BidirectionalClass) != 0 ? (BidirectionalClass)reader.ReadByte() : 0;
@@ -90,11 +152,19 @@ namespace System.Unicode
string simpleTitleCaseMapping = (fields & UcdFields.SimpleTitleCaseMapping) != 0 ? reader.ReadString() : null;
ContributoryProperties contributoryProperties = (fields & UcdFields.ContributoryProperties) != 0 ? (ContributoryProperties)reader.ReadInt32() : 0;
CoreProperties coreProperties = (fields & UcdFields.CoreProperties) != 0 ? (CoreProperties)ReadInt24(reader) : 0;
int[] crossReferences = (fields & UcdFields.CrossRerefences) != 0 ? new int[reader.ReadByte() + 1] : null;
if (crossReferences != null)
{
for (int i = 0; i < crossReferences.Length; ++i)
crossReferences[i] = ReadCodePoint(reader);
}
return new UnicodeCharacterData
(
codePointRange,
name,
nameAliases,
category,
canonicalCombiningClass,
bidirectionalClass,
@@ -109,9 +179,9 @@ namespace System.Unicode
simpleTitleCaseMapping,
contributoryProperties,
coreProperties,
null
crossReferences
);
}
}
private static UnihanCharacterData ReadUnihanCharacterDataEntry(BinaryReader reader)
{
@@ -124,6 +194,18 @@ namespace System.Unicode
reader.ReadInt64() :
0;
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts = (fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0 ?
new UnicodeRadicalStrokeCount
[
(fields & UnihanFields.UnicodeRadicalStrokeCountMore) == UnihanFields.UnicodeRadicalStrokeCountMore ?
reader.ReadByte() + 3 :
((byte)(fields & UnihanFields.UnicodeRadicalStrokeCountMore) >> 2)
] :
UnicodeRadicalStrokeCount.EmptyArray;
for (int i = 0; i < unicodeRadicalStrokeCounts.Length; ++i)
unicodeRadicalStrokeCounts[i] = new UnicodeRadicalStrokeCount(reader.ReadByte(), reader.ReadByte());
string definition = (fields & UnihanFields.Definition) != 0 ? reader.ReadString() : null;
string mandarinReading = (fields & UnihanFields.MandarinReading) != 0 ? reader.ReadString() : null;
string cantoneseReading = (fields & UnihanFields.CantoneseReading) != 0 ? reader.ReadString() : null;
@@ -140,6 +222,7 @@ namespace System.Unicode
codePoint,
numericType,
numericValue,
unicodeRadicalStrokeCounts,
definition,
mandarinReading,
cantoneseReading,
@@ -153,9 +236,20 @@ 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());
return new UnicodeBlock(new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
}
private static int ReadInt24(BinaryReader reader)
@@ -183,15 +277,31 @@ namespace System.Unicode
else
{
return 0x40A0 + (((((b & 0x1F) << 8) | reader.ReadByte()) << 8) | reader.ReadByte());
}
}
}
public static Version UnicodeVersion { get { return unicodeVersion; } }
private static UnicodeCharacterData FindUnicodeCodePoint(int codePoint)
{
int minIndex = 0;
int maxIndex = unicodeCharacterData.Length - 1;
// For the first code points (this includes all of ASCII, and quite a bit more), the index in the table will be the code point itself.
if (codePoint <= maxContiguousIndex)
{
return unicodeCharacterData[codePoint];
}
else
{
// For other code points, we will use a classic binary search with adjusted search indexes.
return BinarySearchUnicodeCodePoint(codePoint);
}
}
private static UnicodeCharacterData BinarySearchUnicodeCodePoint(int codePoint)
{
// NB: Due to the strictly ordered nature of the table, we know that a code point can never happen after the index which is the code point itself.
// This will greatly reduce the range to scan for characters close to maxContiguousIndex, and will have a lesser impact on other characters.
int minIndex = maxContiguousIndex + 1;
int maxIndex = codePoint < unicodeCharacterData.Length ? codePoint - 1 : unicodeCharacterData.Length - 1;
do
{
@@ -212,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;
}
@@ -250,42 +360,121 @@ namespace System.Unicode
return -1;
}
private static string GetBlockName(int codePoint)
/// <summary>Gets the name of the Unicode block containing the character.</summary>
/// <remarks>If the character has not been assigned to a block, the value of <see cref="DefaultBlock"/> will be returned.</remarks>
/// <param name="codePoint">The Unicode code point whose block should be retrieved.</param>
/// <returns>The name of the block the code point was assigned to.</returns>
public static string GetBlockName(int codePoint)
{
int i = FindBlockIndex(codePoint);
return i >= 0 ? blocks[i].Name : null;
}
return i >= 0 ? blocks[i].Name : DefaultBlock;
}
/// <summary>Gets Unicode information on the specified code point.</summary>
/// <remarks>
/// 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:
/// <list type="bullet">
/// <listheader>
/// <term>Property</term>
/// <description>Method</description>
/// </listheader>
/// <item>
/// <term>Name</term>
/// <description><see cref="GetName(int)"/></description>
/// </item>
/// <item>
/// <term>Category</term>
/// <description><see cref="GetCategory(int)"/></description>
/// </item>
/// <item>
/// <term>Block</term>
/// <description><see cref="GetBlockName(int)"/></description>
/// </item>
/// </list>
/// </remarks>
/// <param name="codePoint">The Unicode code point for which the data must be retrieved.</param>
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
public static UnicodeCharInfo GetCharInfo(int codePoint)
{
return new UnicodeCharInfo(codePoint, FindUnicodeCodePoint(codePoint), FindUnihanCodePoint(codePoint), GetBlockName(codePoint));
}
/// <summary>Gets the category of the specified code point.</summary>
/// <remarks>
/// 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 <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Category"/>, because there is less information to lookup.
/// </remarks>
/// <param name="codePoint">The Unicode code point for which the category must be retrieved.</param>
/// <returns>The category of the code point.</returns>
public static UnicodeCategory GetCategory(int codePoint)
{
var charInfo = FindUnicodeCodePoint(codePoint);
var charData = FindUnicodeCodePoint(codePoint);
return charInfo != null ? charInfo.Category : UnicodeCategory.OtherNotAssigned;
}
return charData != null ? charData.Category : UnicodeCategory.OtherNotAssigned;
}
/// <summary>Gets a display text for the specified code point.</summary>
/// <param name="charInfo">The information for the code point.</param>
/// <returns>A display text for the code point, which may be the representation of the code point itself.</returns>
public static string GetDisplayText(UnicodeCharInfo charInfo)
{
if (charInfo.CodePoint <= 0x0020) return ((char)(0x2400 + charInfo.CodePoint)).ToString();
else if (charInfo.Category == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(charInfo.CodePoint);
else return char.ConvertFromUtf32(charInfo.CodePoint);
}
}
/// <summary>Gets a display text for the specified code point.</summary>
/// <param name="codePoint">The Unicode code point, for which a display text should be returned.</param>
/// <returns>A display text for the code point, which may be the representation of the code point itself.</returns>
public static string GetDisplayText(int codePoint)
{
if (codePoint <= 0x0020) return ((char)(0x2400 + codePoint)).ToString();
else if (GetCategory(codePoint) == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(codePoint);
else return char.ConvertFromUtf32(codePoint);
}
}
/// <summary>Gets the name of the specified code point.</summary>
/// <remarks>
/// 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 <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Name"/>, because there is less information to lookup.
/// </remarks>
/// <param name="codePoint">The Unicode code point for which the name must be retrieved.</param>
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
public static string GetName(int codePoint)
{
if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
else return GetName(codePoint, FindUnicodeCodePoint(codePoint));
}
internal static string GetName(int codePoint, UnicodeCharacterData characterData)
{
if (characterData.CodePointRange.IsSingleCodePoint) return characterData.Name;
else if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
else if (characterData.Name != null) return characterData.Name + "-" + codePoint.ToString("X4");
else return null;
}
/// <summary>Returns information for a CJK radical.</summary>
/// <param name="radicalIndex">The index of the radical. Must be between 1 and <see cref="CjkRadicalCount"/>.</param>
/// <returns>Information on the specified radical.</returns>
/// <exception cref="IndexOutOfRangeException">The <paramref name="radicalIndex"/> parameter is out of range.</exception>
public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex)
{
return new CjkRadicalInfo(checked((byte)radicalIndex), radicals[radicalIndex - 1]);
}
/// <summary>Returns the number of CJK radicals in the Unicode data.</summary>
/// <remarks>This value will be 214 for the foreseeable future.</remarks>
public static int CjkRadicalCount { get { return radicals.Length; } }
/// <summary>Gets all the blocks defined in the Unicode data.</summary>
/// <remarks><see cref="DefaultBlock"/> is not the name of a block, but only a value indicating the abscence of block information for a given code point.</remarks>
/// <returns>An array containing an entry for every block defined in the Unicode data.</returns>
public static UnicodeBlock[] GetBlocks()
{
return (UnicodeBlock[])blocks.Clone();
}
}
}
}
+18 -2
View File
@@ -3,7 +3,7 @@
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{CB722958-A1C4-4121-804B-7D5A671491B1}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -32,6 +32,8 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@@ -40,6 +42,8 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
@@ -58,13 +62,22 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Include="..\AssemblyInfo.Common.cs">
<Link>Properties\AssemblyInfo.Common.cs</Link>
</Compile>
<Compile Include="BidirectionalClass.cs" />
<Compile Include="CjkRadicalData.cs" />
<Compile Include="CjkRadicalInfo.cs" />
<Compile Include="CompatibilityFormattingTag.cs" />
<Compile Include="ContributoryProperties.cs" />
<Compile Include="CanonicalCombiningClass.cs" />
<Compile Include="CodePointEnumerable.cs" />
<Compile Include="CodePointEnumerator.cs" />
<Compile Include="CoreProperties.cs" />
<Compile Include="HangulInfo.cs" />
<Compile Include="UnicodeCrossReferenceCollection.cs" />
<Compile Include="UnicodeRadicalStrokeCountCollection.cs" />
<Compile Include="UnicodeNameAliasCollection.cs" />
<Compile Include="UcdFields.cs" />
<Compile Include="EnumHelper.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -73,9 +86,12 @@
<Compile Include="UnicodeCategoryExtensions.cs" />
<Compile Include="UnicodeCategoryInfo.cs" />
<Compile Include="UnicodeCharacterData.cs" />
<Compile Include="UnicodeCharacterRange.cs" />
<Compile Include="UnicodeCodePointRange.cs" />
<Compile Include="UnicodeCharInfo.cs" />
<Compile Include="UnicodeInfo.cs" />
<Compile Include="UnicodeNameAlias.cs" />
<Compile Include="UnicodeNameAliasKind.cs" />
<Compile Include="UnicodeRadicalStrokeCount.cs" />
<Compile Include="UnihanNumericType.cs" />
<Compile Include="UnicodeNumericType.cs" />
<Compile Include="UnihanCharacterData.cs" />
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<package >
<metadata>
<id>$id$</id>
<version>$version$</version>
<title>$title$</title>
<authors>$author$</authors>
<owners>$author$</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>https://github.com/GoldenCrystal/NetUnicodeInfo</projectUrl>
<iconUrl>https://raw.githubusercontent.com/GoldenCrystal/NetUnicodeInfo/master/UnicodeCharacterInspector/UnicodeCharacterInspector.ico</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>$description$</description>
<releaseNotes></releaseNotes>
<copyright>Copyright 2014</copyright>
<tags>Unicode Unihan .NET C# String Text Char Character CodePoint Code Point</tags>
</metadata>
</package>
+16
View File
@@ -0,0 +1,16 @@
namespace System.Unicode
{
public struct UnicodeNameAlias
{
internal static readonly UnicodeNameAlias[] EmptyArray = new UnicodeNameAlias[0];
public string Name { get; }
public UnicodeNameAliasKind Kind { get; }
internal UnicodeNameAlias(string name, UnicodeNameAliasKind kind)
{
Name = name;
Kind = kind;
}
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
public struct UnicodeNameAliasCollection : IList<UnicodeNameAlias>
{
public struct Enumerator : IEnumerator<UnicodeNameAlias>
{
private readonly UnicodeNameAlias[] items;
private int index;
internal Enumerator(UnicodeNameAlias[] items)
{
this.items = items;
this.index = -1;
}
public void Dispose() { }
public UnicodeNameAlias Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
private readonly UnicodeNameAlias[] items;
public UnicodeNameAliasCollection() { items = UnicodeNameAlias.EmptyArray; }
internal UnicodeNameAliasCollection(UnicodeNameAlias[] items) { this.items = items ?? UnicodeNameAlias.EmptyArray; }
public UnicodeNameAlias this[int index] { get { return items[index]; } }
UnicodeNameAlias IList<UnicodeNameAlias>.this[int index]
{
get { return items[index]; }
set { throw new NotSupportedException(); }
}
public int Count { get { return items.Length; } }
bool ICollection<UnicodeNameAlias>.IsReadOnly { get { return true; } }
public void Add(UnicodeNameAlias item) { throw new NotSupportedException(); }
public void Insert(int index, UnicodeNameAlias item) { throw new NotSupportedException(); }
public bool Remove(UnicodeNameAlias item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
public int IndexOf(UnicodeNameAlias item) { return Array.IndexOf(items, item); }
public bool Contains(UnicodeNameAlias item) { return IndexOf(item) >= 0; }
public void CopyTo(UnicodeNameAlias[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<UnicodeNameAlias> IEnumerable<UnicodeNameAlias>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
}
@@ -0,0 +1,16 @@
namespace System.Unicode
{
public enum UnicodeNameAliasKind : byte
{
[ValueName("correction")]
Correction = 1,
[ValueName("control")]
Control = 2,
[ValueName("alternate")]
Alternate = 3,
[ValueName("figment")]
Figment = 4,
[ValueName("abbreviation")]
Abbreviation = 5
}
}
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
public struct UnicodeRadicalStrokeCount
{
internal static readonly UnicodeRadicalStrokeCount[] EmptyArray = new UnicodeRadicalStrokeCount[0];
private readonly byte radical;
private readonly byte strokeCount;
internal UnicodeRadicalStrokeCount(byte rawRadical, byte rawStrokeCount)
{
radical = rawRadical;
strokeCount = rawStrokeCount;
}
internal UnicodeRadicalStrokeCount(byte radical, byte strokeCount, bool isSimplified)
{
this.radical = radical;
if (isSimplified) strokeCount |= 0x80;
this.strokeCount = strokeCount;
}
public byte Radical { get { return radical; } }
public byte StrokeCount { get { return (byte)(strokeCount & 0x7F); } }
public bool IsSimplified { get { return (strokeCount & 0x80) != 0; } }
}
}
@@ -0,0 +1,68 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
public struct UnicodeRadicalStrokeCountCollection : IList<UnicodeRadicalStrokeCount>
{
public struct Enumerator : IEnumerator<UnicodeRadicalStrokeCount>
{
private readonly UnicodeRadicalStrokeCount[] items;
private int index;
internal Enumerator(UnicodeRadicalStrokeCount[] items)
{
this.items = items;
this.index = -1;
}
public void Dispose() { }
public UnicodeRadicalStrokeCount Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
private readonly UnicodeRadicalStrokeCount[] items;
public UnicodeRadicalStrokeCountCollection() { items = UnicodeRadicalStrokeCount.EmptyArray; }
internal UnicodeRadicalStrokeCountCollection(UnicodeRadicalStrokeCount[] items) { this.items = items ?? UnicodeRadicalStrokeCount.EmptyArray; }
public UnicodeRadicalStrokeCount this[int index] { get { return items[index]; } }
UnicodeRadicalStrokeCount IList<UnicodeRadicalStrokeCount>.this[int index]
{
get { return items[index]; }
set { throw new NotSupportedException(); }
}
public int Count { get { return items.Length; } }
bool ICollection<UnicodeRadicalStrokeCount>.IsReadOnly { get { return true; } }
public void Add(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
public void Insert(int index, UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
public bool Remove(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
public int IndexOf(UnicodeRadicalStrokeCount item) { return Array.IndexOf(items, item); }
public bool Contains(UnicodeRadicalStrokeCount item) { return IndexOf(item) >= 0; }
public void CopyTo(UnicodeRadicalStrokeCount[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<UnicodeRadicalStrokeCount> IEnumerable<UnicodeRadicalStrokeCount>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
}
+1 -1
View File
@@ -10,7 +10,7 @@ namespace System.Unicode
{
public static UnicodeRationalNumber Parse(string s)
{
if (s == null) throw new ArgumentNullException("s");
if (s == null) throw new ArgumentNullException(nameof(s));
if (s.Length == 0) throw new ArgumentException();
int fractionBarIndex = s.IndexOf('/');
+7 -4
View File
@@ -11,6 +11,7 @@ namespace System.Unicode
public readonly int CodePoint;
public readonly UnihanNumericType NumericType;
public readonly long NumericValue;
public readonly UnicodeRadicalStrokeCount[] UnicodeRadicalStrokeCounts;
public readonly string Definition;
public readonly string MandarinReading;
public readonly string CantoneseReading;
@@ -27,6 +28,7 @@ namespace System.Unicode
int codePoint,
UnihanNumericType numericType,
long numericValue,
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts,
string definition,
string mandarinReading,
string cantoneseReading,
@@ -42,6 +44,7 @@ namespace System.Unicode
CodePoint = codePoint;
NumericType = numericType;
NumericValue = numericValue;
UnicodeRadicalStrokeCounts = unicodeRadicalStrokeCounts;
Definition = definition;
MandarinReading = mandarinReading;
CantoneseReading = cantoneseReading;
@@ -66,10 +69,10 @@ namespace System.Unicode
if (codePoint < 0x2F800) return codePoint - 0x19400;
else if (codePoint < 0x30000) return codePoint - 0x10000;
}
}
}
throw new ArgumentOutOfRangeException("codePoint");
}
throw new ArgumentOutOfRangeException(nameof(codePoint));
}
internal static int UnpackCodePoint(int packedCodePoint)
{
@@ -81,7 +84,7 @@ namespace System.Unicode
else if (packedCodePoint < 0x1F800) return packedCodePoint - 0xFD00;
else if (packedCodePoint < 0x20000) return packedCodePoint + 0x10000;
}
throw new ArgumentOutOfRangeException("packedCodePoint");
throw new ArgumentOutOfRangeException(nameof(packedCodePoint));
}
}
}
+15 -10
View File
@@ -14,16 +14,21 @@ namespace System.Unicode
AccountingNumeric = 2,
OtherNumeric = 3,
Definition = 4,
MandarinReading = 8,
CantoneseReading = 16,
JapaneseKunReading = 32,
JapaneseOnReading = 64,
KoreanReading = 128,
HangulReading = 256,
VietnameseReading = 512,
// UnicodeRadicalStroke : Not exactly a bit mask…
UnicodeRadicalStrokeCount = 4, // Will indicate exactly one value for Unicode_Radical_Stroke.
UnicodeRadicalStrokeCountTwice = 8, // Will indicate exactly two values for Unicode_Radical_Stroke.
UnicodeRadicalStrokeCountMore = 12, // Will indicate three or more values for Unicode_Radical_Stroke. This combination should never happen in the current files.
SimplifiedVariant = 1024,
TraditionalVariant = 2048,
Definition = 16,
MandarinReading = 32,
CantoneseReading = 64,
JapaneseKunReading = 128,
JapaneseOnReading = 256,
KoreanReading = 512,
HangulReading = 1024,
VietnameseReading = 2048,
SimplifiedVariant = 4096,
TraditionalVariant = 8192,
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace System.Unicode
{
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class ValueNameAttribute : Attribute
{
private readonly string name;
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB