38 Commits

Author SHA1 Message Date
swcs 6106f8e7ea update to .NET Standard 2 2018-09-24 14:43:32 +02:00
GoldenCrystal cac4c9de8b Update version information and AppVeyor settings 2017-09-07 23:52:28 +02:00
GoldenCrystal 751e84fc6d Add DebuggerDisplay attributes.
Format some code to C# 7.0.
Remove useless using directives.
2017-09-07 23:10:17 +02:00
GoldenCrystal d65f7f0a77 Use ASCII as display text for "TAG" characters at U+E0000. 2017-06-25 20:09:54 +02:00
GoldenCrystal 642b675b3d Added support for emoji properties. 2017-06-25 17:14:03 +02:00
GoldenCrystal f9976c7a03 Use ref returns to access character data, which should reduce memory consumption a bit.
Reduced some parts of the code by leveraging C# 6 and C# 7 features.
Preliminary work for adding emoji properties to characters.
2017-06-25 02:36:38 +02:00
GoldenCrystal b9d732f561 Tweak the UI configuration to force per-monitor High DPI awareness. 2017-06-24 18:26:28 +02:00
GoldenCrystal 8238c532ec Fix NuGet package title. 2017-06-24 14:52:14 +02:00
GoldenCrystal 968130e59e Swap arguments in Assert.Equal. 2017-06-24 14:20:40 +02:00
GoldenCrystal 04211241bc Trying to fix tests again. 2017-06-24 14:12:59 +02:00
GoldenCrystal bce0e6e20b Fix dotnet-xunit version. 2017-06-24 13:44:33 +02:00
GoldenCrystal 91b1d3b2ef Try to fix the appveyor build. 2017-06-24 13:32:04 +02:00
GoldenCrystal 87e5c4a523 Upgrade AppVeyor configuration 2017-06-21 02:36:08 +02:00
GoldenCrystal ca267468e5 Update to Unicode 10.0.
Migrate to new MSBuild project format.
Migrate main lib to .NET Standard 1.1.
Fix a bug in parsing UCD files.
2017-06-21 02:28:58 +02:00
GoldenCrystal 660fbd49f2 This need to be version 2.0.0… 2016-08-09 00:28:04 +02:00
GoldenCrystal e6ace93e19 Force NuGet package restore before AppVeyor build. 2016-08-09 00:23:33 +02:00
GoldenCrystal de6140734f Separated UnicodeCodePointRange tests. 2016-08-09 00:18:58 +02:00
GoldenCrystal a997a88505 Split tests in more classes. 2016-08-09 00:18:57 +02:00
GoldenCrystal c7230ad446 Parameterized some unit tests. 2016-08-09 00:18:57 +02:00
GoldenCrystal 24909bf28d Migrate to Xunit and start revamping unit tests. 2016-08-09 00:18:56 +02:00
GoldenCrystal 58e4cc8802 Migrate database and project to Unicode 9.0.0. 2016-08-09 00:18:46 +02:00
GoldenCrystal 301d7b6e98 Bugfix again :( 2016-01-14 01:46:15 +01:00
GoldenCrystal a09eef8196 Upgrade appveyor configuration. 2016-01-14 01:36:58 +01:00
GoldenCrystal 23823a6626 Bugfixes. 2016-01-14 01:31:36 +01:00
GoldenCrystal 3cf36ec6de Upgrade AppVeyor configuration again, to force the use of MSBuild 14.0. 2015-07-19 02:50:51 +02:00
GoldenCrystal ff47b6a9f1 Upgrade the AppVeyor configuration to use VS 2015 RC for the builds. 2015-07-19 02:31:16 +02:00
GoldenCrystal e3cada4ca7 Try to determine the Unicode version dynamically from the data files, in the hope to ease upgrades to future Unicode versions. 2015-07-19 02:28:53 +02:00
GoldenCrystal 07b4086423 Upgrade for Unicode Version 8.0.0. 2015-07-19 01:56:28 +02:00
GoldenCrystal a429d83bdb Fix a few bugs, and compensate removal of parameterless constructors for structs in C# 6.0 2015-07-19 01:54:17 +02:00
GoldenCrystal f0b7ccb607 Xml documentation… Done! 2014-12-16 02:48:50 +01:00
GoldenCrystal 04b03edee2 Added even more XML documentaion tags. 2014-12-16 02:32:00 +01:00
GoldenCrystal 6b4e1da5bf Masked some unsupported IList<T> and ICollection<T> members.
Added more XML documentation tags.
2014-12-16 00:53:15 +01:00
GoldenCrystal bc07cc9b55 Added XML documentation on some members. 2014-12-15 01:57:09 +01:00
GoldenCrystal 63fd694c26 Configure AppVeyor for publishing to NuGet. 2014-12-14 11:45:28 +01:00
GoldenCrystal 0012ef2434 Updated NuGet spec and AppVeyor.yml. 2014-12-14 11:13:33 +01:00
GoldenCrystal 4f5ac9d555 Add AppVeyor configuration file. 2014-12-14 10:59:40 +01:00
GoldenCrystal da53411d30 Added an AppVeyor badge. 2014-12-14 03:49:59 +01:00
GoldenCrystal fd2e8122ed Added a permissive code point enumerator, which doesn't choke on lone surrogates. 2014-11-26 22:27:09 +01:00
75 changed files with 2301 additions and 1442 deletions
+2 -1
View File
@@ -18,6 +18,7 @@ bld/
# Roslyn cache directories
*.ide/
.vs/
# MSTest test Results
[Tt]est[Rr]esult*/
@@ -186,4 +187,4 @@ FakesAssemblies/
# LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
ModelManifest.xml
+2 -2
View File
@@ -15,5 +15,5 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyVersion("2.2.0.0")]
[assembly: AssemblyFileVersion("2.2.0.0")]
+10
View File
@@ -0,0 +1,10 @@
<Project>
<PropertyGroup>
<Product>.NET Unicode Information</Product>
<Authors>Fabien Barbier, Tobias Klika</Authors>
<Copyright>Copyright © Fabien Barbier 2014-2017, © Tobias Klika 2018</Copyright>
<NeutralLanguage>en</NeutralLanguage>
<Version>2.3.0</Version>
<PackageVersion>2.3.0</PackageVersion>
</PropertyGroup>
</Project>
+12 -1
View File
@@ -1,18 +1,29 @@
Unicode Character Inspector & .NET Unicode Information Library
==============================================================
[![Build status](https://ci.appveyor.com/api/projects/status/github/GoldenCrystal/NetUnicodeInfo?branch=master&svg=true)](https://ci.appveyor.com/project/GoldenCrystal/netunicodeinfo/branch/master)
Summary
-------
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.
Version of Unicode supported
----------------------------
Unicode 10.0.0
Emoji 5.0
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)
Breaking changes from versions 1.x to 2.x
-----------------------------------------
UnicodeRadicalStrokeCount.StrokeCount is now of type System.SByte instead of type System.Byte.
Compiling and using the project
-------------------------------
### Using the UnicodeInformation library
@@ -54,7 +65,7 @@ This example shows a few usages of the library. It gets information on a specifi
### Details
In its current state, the project is written in C# 6, compilable by [Roslyn](http://roslyn.codeplex.com/), and targets the .NET 4.5 framework.
The core of the project, UnicodeInformation.dll, is a portable class library usable for either regular .NET or Windows 8 applications.
This library includes a subset of the official [Unicode Character Database](http://www.unicode.org/Public/UCD/latest/) (Version 7.0 at the time of writing) stored in a custom file format.
This library includes a subset of the official [Unicode Character Database](http://www.unicode.org/Public/UCD/latest/) stored in a custom file format.
### Included Properties
#### From UCD
+12 -3
View File
@@ -1,6 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<startup>
<supportedRuntime version="v4.7" sku=".NETFramework,Version=v4.7"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<runtime>
<AppContextSwitchOverrides value = "Switch.System.Windows.DoNotScaleForDpiChanges=false"/>
</runtime>
</configuration>
+10
View File
@@ -15,9 +15,19 @@
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<highResolutionScrollingAware xmlns="http://schemas.microsoft.com/SMI/2013/WindowsSettings">true</highResolutionScrollingAware>
<ultraHighResolutionScrollingAware xmlns="http://schemas.microsoft.com/SMI/2013/WindowsSettings">true</ultraHighResolutionScrollingAware>
</windowsSettings>
</application>
<dependency>
<dependentAssembly>
<assemblyIdentity
+2 -1
View File
@@ -10,6 +10,7 @@
<local:Utf32ToDisplayTextConverter x:Key="Utf32ToDisplayTextConverter" />
<local:Utf32ToNameConverter x:Key="Utf32ToNameConverter" />
<local:StringToUtf32Converter x:Key="StringToUtf32Converter" />
<local:RadicalStrokeCountToCharConverter x:Key="RadicalStrokeCountToCharConverter" />
<local:RadicalStrokeCountToCharConverter x:Key="RadicalStrokeCountToCharConverter" />
<local:CodePointToFontFamilyConverter x:Key="CodePointToFontFamilyConverter" DefaultFontFamily="Segoe UI" EmojiFontFamily="Segoe UI Emoji" />
</Application.Resources>
</Application>
@@ -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.Unicode;
namespace UnicodeCharacterInspector
@@ -67,6 +63,7 @@ namespace UnicodeCharacterInspector
NotifyPropertyChanged(nameof(NumericValue));
NotifyPropertyChanged(nameof(ContributoryProperties));
NotifyPropertyChanged(nameof(CoreProperties));
NotifyPropertyChanged(nameof(EmojiProperties));
NotifyPropertyChanged(nameof(RadicalStrokeCounts));
NotifyPropertyChanged(nameof(CrossReferences));
NotifyPropertyChanged(nameof(MandarinReading));
@@ -88,145 +85,49 @@ namespace UnicodeCharacterInspector
displayText = character != null ? UnicodeInfo.GetDisplayText(characterInfo) : null;
if (displayText != oldValue)
NotifyPropertyChanged(nameof(DisplayText));
if (displayText != oldValue) NotifyPropertyChanged(nameof(DisplayText));
}
public string DisplayText { get { return displayText; } }
public string DisplayText => displayText;
public int? CodePoint
{
get { return character != null ? codePoint : null as int?; }
}
public int? CodePoint => character != null ? codePoint : null as int?;
public string Name
{
get { return character != null ? characterInfo.Name : null; }
}
public string Name => character != null ? characterInfo.Name : null;
public string OldName => character != null ? characterInfo.OldName : null;
public UnicodeNameAliasCollection NameAliases => character != null ? characterInfo.NameAliases : UnicodeNameAliasCollection.Empty;
public UnicodeNameAliasCollection NameAliases
{
get { return character != null ? characterInfo.NameAliases : new UnicodeNameAliasCollection(); }
}
public string Definition => character != null ? characterInfo.Definition : null;
public string OldName
{
get { return character != null ? characterInfo.OldName : null; }
}
public UnicodeCategory? Category => character != null ? characterInfo.Category : null as UnicodeCategory?;
public string Block => character != null ? characterInfo.Block : null;
public string Definition
{
get { return character != null ? characterInfo.Definition : null; }
}
public CanonicalCombiningClass? CanonicalCombiningClass => character != null ? characterInfo.CanonicalCombiningClass : null as CanonicalCombiningClass?;
public BidirectionalClass? BidirectionalClass => character != null ? characterInfo.BidirectionalClass : null as BidirectionalClass?;
public CompatibilityFormattingTag? DecompositionType => character != null && characterInfo.DecompositionMapping != null ? characterInfo.DecompositionType : null as CompatibilityFormattingTag?;
public UnicodeCategory? Category
{
get { return character != null ? characterInfo.Category : null as UnicodeCategory?; }
}
public string DecompositionMapping => character != null ? characterInfo.DecompositionMapping : null;
public string Block
{
get { return character != null ? characterInfo.Block : null; }
}
public UnicodeNumericType? NumericType => character != null ? characterInfo.NumericType : null as UnicodeNumericType?;
public UnihanNumericType? UnihanNumericType => character != null ? characterInfo.UnihanNumericType : null as UnihanNumericType?;
public UnicodeRationalNumber? NumericValue => character != null && characterInfo.NumericType != UnicodeNumericType.None ? characterInfo.NumericValue : null as UnicodeRationalNumber?;
public CanonicalCombiningClass? CanonicalCombiningClass
{
get { return character != null ? characterInfo.CanonicalCombiningClass : null as CanonicalCombiningClass?; }
}
public ContributoryProperties? ContributoryProperties => character != null ? characterInfo.ContributoryProperties : null as ContributoryProperties?;
public CoreProperties? CoreProperties => character != null ? characterInfo.CoreProperties : null as CoreProperties?;
public EmojiProperties? EmojiProperties => character != null ? characterInfo.EmojiProperties : null as EmojiProperties?;
public BidirectionalClass? BidirectionalClass
{
get { return character != null ? characterInfo.BidirectionalClass : null as BidirectionalClass?; }
}
public UnicodeRadicalStrokeCountCollection RadicalStrokeCounts => character != null ? characterInfo.UnicodeRadicalStrokeCounts : UnicodeRadicalStrokeCountCollection.Empty;
public CompatibilityFormattingTag? DecompositionType
{
get { return character != null && characterInfo.DecompositionMapping != null ? characterInfo.DecompositionType : null as CompatibilityFormattingTag?; }
}
public UnicodeCrossReferenceCollection CrossReferences => character != null ? characterInfo.CrossRerefences : UnicodeCrossReferenceCollection.Empty;
public string DecompositionMapping
{
get { return character != null ? characterInfo.DecompositionMapping : null; }
}
public string MandarinReading => character != null ? characterInfo.MandarinReading : null;
public string CantoneseReading => character != null ? characterInfo.CantoneseReading : null;
public string JapaneseKunReading => character != null ? characterInfo.JapaneseKunReading : null;
public string JapaneseOnReading => character != null ? characterInfo.JapaneseOnReading : null;
public string KoreanReading => character != null ? characterInfo.KoreanReading : null;
public string HangulReading => character != null ? characterInfo.HangulReading : null;
public string VietnameseReading => character != null ? characterInfo.VietnameseReading : null;
public UnicodeNumericType? NumericType
{
get { return character != null ? characterInfo.NumericType : null as UnicodeNumericType?; }
}
public UnihanNumericType? UnihanNumericType
{
get { return character != null ? characterInfo.UnihanNumericType : null as UnihanNumericType?; }
}
public UnicodeRationalNumber? NumericValue
{
get { return character != null && characterInfo.NumericType != UnicodeNumericType.None ? characterInfo.NumericValue : null as UnicodeRationalNumber?; }
}
public ContributoryProperties? ContributoryProperties
{
get { return character != null ? characterInfo.ContributoryProperties : null as ContributoryProperties?; }
}
public CoreProperties? CoreProperties
{
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; }
}
public string CantoneseReading
{
get { return character != null ? characterInfo.CantoneseReading : null; }
}
public string JapaneseKunReading
{
get { return character != null ? characterInfo.JapaneseKunReading : null; }
}
public string JapaneseOnReading
{
get { return character != null ? characterInfo.JapaneseOnReading : null; }
}
public string KoreanReading
{
get { return character != null ? characterInfo.KoreanReading : null; }
}
public string HangulReading
{
get { return character != null ? characterInfo.HangulReading : null; }
}
public string VietnameseReading
{
get { return character != null ? characterInfo.VietnameseReading : null; }
}
public string SimplifiedVariant
{
get { return character != null ? characterInfo.SimplifiedVariant : null; }
}
public string TraditionalVariant
{
get { return character != null ? characterInfo.TraditionalVariant : null; }
}
public string SimplifiedVariant => character != null ? characterInfo.SimplifiedVariant : null;
public string TraditionalVariant => character != null ? characterInfo.TraditionalVariant : null;
}
}
@@ -139,7 +139,7 @@ namespace UnicodeCharacterInspector
int index = 0;
if (!string.IsNullOrEmpty(value))
{
foreach (int codePoint in value.AsCodePointEnumerable())
foreach (int codePoint in value.AsPermissiveCodePointEnumerable())
{
if (index >= codePoints.Length) Array.Resize(ref codePoints, codePoints.Length * 2);
@@ -0,0 +1,23 @@
using System;
using System.Globalization;
using System.Unicode;
using System.Windows.Data;
using System.Windows.Media;
namespace UnicodeCharacterInspector
{
internal sealed class CodePointToFontFamilyConverter : IValueConverter
{
public FontFamily DefaultFontFamily { get; set; }
public FontFamily EmojiFontFamily { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> value is int codePoint && UnicodeInfo.GetCharInfo(codePoint).EmojiProperties != 0 ?
EmojiFontFamily :
DefaultFontFamily;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}
}
+9 -6
View File
@@ -38,14 +38,14 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<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 Grid.Row="1" Grid.RowSpan="3" ItemsSource="{Binding Characters}" SelectedIndex="{Binding SelectedCharacterIndex}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock><Run Text="{Binding DisplayText, Mode=OneWay}" /> <Run Text="{Binding CodePoint, Mode=OneWay, StringFormat=U+{0:X4}}" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" FontStyle="Italic" /></TextBlock>
<TextBlock FontFamily="{Binding CodePoint, Mode=OneWay, Converter={StaticResource CodePointToFontFamilyConverter}}"><Run Text="{Binding DisplayText, Mode=OneWay}" /> <Run Text="{Binding CodePoint, Mode=OneWay, StringFormat=U+{0:X4}}" Foreground="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" FontStyle="Italic" /></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<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" />
<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" FontFamily="{Binding SelectedCharacterInfo.CodePoint, Mode=OneWay, Converter={StaticResource CodePointToFontFamilyConverter}}" />
<ScrollViewer Grid.Row="2" Grid.Column="1" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.Resources>
@@ -86,7 +86,8 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
@@ -158,8 +159,10 @@
<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}">
<TextBlock Grid.Row="25" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.EmojiProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Emoji Properties" />
<TextBlock Grid.Row="25" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.EmojiProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.EmojiProperties}" />
<TextBlock Grid.Row="26" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Cross-References" />
<ItemsControl Grid.Row="26" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CrossReferences.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.CrossReferences}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock TextWrapping="WrapWithOverflow">
@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnicodeCharacterInspector</RootNamespace>
<AssemblyName>UnicodeCharacterInspector</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
@@ -42,9 +42,9 @@
<PropertyGroup>
<ApplicationIcon>UnicodeCharacterInspector.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup>
<UICulture>en-US</UICulture>
</PropertyGroup>
<PropertyGroup>
<UICulture>en-US</UICulture>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
@@ -79,6 +79,7 @@
<Compile Include="BindableObject.cs" />
<Compile Include="CharacterInfoViewModel.cs" />
<Compile Include="CharacterInspectorViewModel.cs" />
<Compile Include="CodePointToFontFamilyConverter.cs" />
<Compile Include="Placeholder.cs" />
<Compile Include="PlaceholderAdorner.cs">
<DependentUpon>Placeholder.cs</DependentUpon>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
+33
View File
@@ -0,0 +1,33 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace System.Unicode.Builder
{
internal static class EnumHelper<T>
where T : struct
{
private static readonly Dictionary<string, T> namedValueDictionary = CreateNamedValueDictionary();
private static Dictionary<string, T> CreateNamedValueDictionary()
{
var type = typeof(T).GetTypeInfo();
if (!type.IsEnum) throw new InvalidOperationException();
return
(
from field in type.DeclaredFields
where field.IsPublic && field.IsLiteral
from attr in field.GetCustomAttributes<ValueNameAttribute>()
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)
{
return namedValueDictionary.TryGetValue(name, out value);
}
}
}
+4 -15
View File
@@ -1,28 +1,17 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode.Builder
{
public class HttpDataSource : IDataSource
{
public static readonly Uri UnicodeCharacterDataUri = new Uri("http://www.unicode.org/Public/UCD/latest/ucd/", UriKind.Absolute);
private readonly HttpClient httpClient;
private readonly Uri baseUri;
public HttpDataSource()
: this(UnicodeCharacterDataUri)
public HttpDataSource(Uri baseUri, HttpClient httpClient)
{
}
public HttpDataSource(Uri baseUri)
{
this.httpClient = new HttpClient();
this.httpClient = httpClient ?? new HttpClient();
this.baseUri = baseUri;
}
+31 -27
View File
@@ -11,6 +11,9 @@ namespace System.Unicode.Builder
{
internal class Program
{
public static readonly Uri UnicodeCharacterDataUri = new Uri("http://www.unicode.org/Public/UCD/latest/ucd/", UriKind.Absolute);
public static readonly Uri EmojiDataUri = new Uri("http://www.unicode.org/Public/emoji/latest/", UriKind.Absolute);
public const string UnihanDirectoryName = "Unihan";
public const string UnihanArchiveName = "Unihan.zip";
public const string UcdDirectoryName = "UCD";
@@ -36,26 +39,30 @@ namespace System.Unicode.Builder
"Unihan_IRGSources.txt",
};
private static HttpMessageHandler httpMessageHandler;
public static readonly string[] emojiRequiredFiles = new[]
{
"emoji-data.txt",
"emoji-sequences.txt",
"emoji-variation-sequences.txt",
"emoji-zwj-sequences.txt",
};
private static HttpClient httpClient;
// The only purpose of this is for tests…
internal static HttpMessageHandler HttpMessageHandler
internal static void SetHttpMessageHandler(HttpMessageHandler handler)
{
get { return httpMessageHandler ?? (httpMessageHandler = new HttpClientHandler()); }
set { httpMessageHandler = value != null ? value : new HttpClientHandler(); }
httpClient = new HttpClient(handler ?? new HttpClientHandler());
}
private static byte[] DownloadDataArchive(string archiveName)
{
using (var httpClient = new HttpClient(HttpMessageHandler))
{
return httpClient.GetByteArrayAsync(HttpDataSource.UnicodeCharacterDataUri + archiveName).Result;
}
}
internal static HttpClient HttpClient { get { return httpClient ?? (httpClient = new HttpClient()); } }
internal static IDataSource GetDataSource(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
private static Task<byte[]> DownloadDataArchiveAsync(string archiveName)
=> HttpClient.GetByteArrayAsync(UnicodeCharacterDataUri + archiveName);
internal static async Task<IDataSource> GetDataSourceAsync(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
{
string baseDirectory = Environment.CurrentDirectory;
string baseDirectory = Directory.GetCurrentDirectory();
string dataDirectory = Path.Combine(baseDirectory, UcdDirectoryName);
string dataArchiveFileName = Path.Combine(baseDirectory, archiveName);
@@ -96,15 +103,14 @@ namespace System.Unicode.Builder
if (shouldDownload != false)
{
var dataArchiveData = DownloadDataArchive(archiveName);
var dataArchiveData = await DownloadDataArchiveAsync(archiveName).ConfigureAwait(false);
if (shouldSaveArchive == true)
{
var stream = File.Open(dataArchiveFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read);
try
using (var stream = File.Open(dataArchiveFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
{
stream.Write(dataArchiveData, 0, dataArchiveData.Length);
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
await stream.WriteAsync(dataArchiveData, 0, dataArchiveData.Length).ConfigureAwait(false);
dataArchiveData = null; // Release the reference now, since we won't need it anymore.
if (shouldExtract == true)
{
@@ -120,11 +126,6 @@ namespace System.Unicode.Builder
return new ZipDataSource(stream);
}
}
catch
{
stream.Dispose();
throw;
}
}
else
{
@@ -135,18 +136,21 @@ namespace System.Unicode.Builder
throw new InvalidOperationException();
}
private static void Main(string[] args)
private static async Task MainAsync(string[] args)
{
UnicodeInfoBuilder data;
using (var ucdSource = GetDataSource(UcdArchiveName, UcdDirectoryName, ucdRequiredFiles, null, null, null))
using (var unihanSource = GetDataSource(UnihanArchiveName, UnihanDirectoryName, unihanRequiredFiles, null, null, null))
using (var ucdSource = await GetDataSourceAsync(UcdArchiveName, UcdDirectoryName, ucdRequiredFiles, null, null, null))
using (var unihanSource = await GetDataSourceAsync(UnihanArchiveName, UnihanDirectoryName, unihanRequiredFiles, null, null, null))
using (var emojiSource = new HttpDataSource(EmojiDataUri, HttpClient))
{
data = UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource).Result;
data = await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource, emojiSource);
}
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
data.WriteToStream(stream);
}
private static void Main(string[] args) => MainAsync(args).Wait();
}
}
@@ -1,8 +1,3 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("UnicodeInformation.Builder")]
[assembly: AssemblyDescription("Data file builder for the .NET Unicode Information Library.")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
@@ -1,129 +1,44 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode.Builder
{
public sealed class UnicodeCharacterDataBuilder
{
private readonly UnicodeCodePointRange codePointRange;
private string name;
private UnicodeCategory category = UnicodeCategory.OtherNotAssigned;
private CanonicalCombiningClass canonicalCombiningClass;
private BidirectionalClass bidirectionalClass;
private CharacterDecompositionMapping characterDecompositionMapping;
private UnicodeNumericType numericType;
private UnicodeRationalNumber numericValue;
private bool bidirectionalMirrored;
private string oldName;
private string simpleUpperCaseMapping;
private string simpleLowerCaseMapping;
private string simpleTitleCaseMapping;
private ContributoryProperties contributoryProperties;
private CoreProperties coreProperties;
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
private readonly List<int> crossRerefences = new List<int>();
public UnicodeCodePointRange CodePointRange { get { return codePointRange; } }
public UnicodeCodePointRange CodePointRange { get; }
public string Name
{
get { return name; }
set { name = value; }
}
public string Name { get; set; }
public IList<UnicodeNameAlias> NameAliases { get { return nameAliases; } }
public UnicodeCategory Category
{
get { return category; }
set
{
if (!Enum.IsDefined(typeof(UnicodeCategory), value))
{
throw new ArgumentOutOfRangeException(nameof(value));
}
category = value;
}
}
public CanonicalCombiningClass CanonicalCombiningClass
{
get { return canonicalCombiningClass; }
set { canonicalCombiningClass = value; } // Even values not defined in the enum are allowed here.
}
public BidirectionalClass BidirectionalClass
{
get { return bidirectionalClass; }
set { bidirectionalClass = value; }
}
public CharacterDecompositionMapping CharacterDecompositionMapping
{
get { return characterDecompositionMapping; }
set { characterDecompositionMapping = value; }
}
public UnicodeNumericType NumericType
{
get { return numericType; }
set { numericType = value; }
}
public UnicodeRationalNumber NumericValue
{
get { return numericValue; }
set { numericValue = value; }
}
public string OldName
{
get { return oldName; }
set { oldName = value; }
}
public bool BidirectionalMirrored
{
get { return bidirectionalMirrored; }
set { bidirectionalMirrored = value; }
}
public string SimpleUpperCaseMapping
{
get { return simpleUpperCaseMapping; }
set { simpleUpperCaseMapping = value; }
}
public string SimpleLowerCaseMapping
{
get { return simpleLowerCaseMapping; }
set { simpleLowerCaseMapping = value; }
}
public string SimpleTitleCaseMapping
{
get { return simpleTitleCaseMapping; }
set { simpleTitleCaseMapping = value; }
}
public ContributoryProperties ContributoryProperties
{
get { return contributoryProperties; }
set { contributoryProperties = value; }
}
public CoreProperties CoreProperties
{
get { return coreProperties; }
set { coreProperties = value; }
get => category;
set => category = Enum.IsDefined(typeof(UnicodeCategory), value) ?
value :
throw new ArgumentOutOfRangeException(nameof(value));
}
public CanonicalCombiningClass CanonicalCombiningClass { get; set; } // Even values not defined in the enum are allowed here.
public BidirectionalClass BidirectionalClass { get; set; }
public CharacterDecompositionMapping CharacterDecompositionMapping { get; set; }
public UnicodeNumericType NumericType { get; set; }
public UnicodeRationalNumber NumericValue { get; set; }
public string OldName { get; set; }
public bool BidirectionalMirrored { get; set; }
public string SimpleUpperCaseMapping { get; set; }
public string SimpleLowerCaseMapping { get; set; }
public string SimpleTitleCaseMapping { get; set; }
public ContributoryProperties ContributoryProperties { get; set; }
public CoreProperties CoreProperties { get; set; }
public EmojiProperties EmojiProperties { get; set; }
public IList<int> CrossRerefences { get { return crossRerefences; } }
public UnicodeCharacterDataBuilder(int codePoint)
@@ -133,7 +48,7 @@ namespace System.Unicode.Builder
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
{
this.codePointRange = codePointRange;
CodePointRange = codePointRange;
this.category = UnicodeCategory.OtherNotAssigned;
}
@@ -143,7 +58,7 @@ namespace System.Unicode.Builder
(
CodePointRange,
Name,
NameAliases.Count > 0 ? NameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
nameAliases.Count > 0 ? nameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
Category,
CanonicalCombiningClass,
BidirectionalClass,
@@ -157,7 +72,7 @@ namespace System.Unicode.Builder
SimpleLowerCaseMapping,
SimpleTitleCaseMapping,
ContributoryProperties,
CoreProperties,
(int)CoreProperties | (int)EmojiProperties << 20,
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
);
}
@@ -168,27 +83,27 @@ namespace System.Unicode.Builder
UcdFields fields = default(UcdFields);
if (!codePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
if (!CodePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
if (name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
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 (CanonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
/*if (bidirectionalClass != 0)*/
fields |= UcdFields.BidirectionalClass;
if (characterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
fields |= (UcdFields)((int)numericType << 6);
if (bidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
if (oldName != null) fields |= UcdFields.OldName;
if (simpleUpperCaseMapping != null) fields |= UcdFields.SimpleUpperCaseMapping;
if (simpleLowerCaseMapping != null) fields |= UcdFields.SimpleLowerCaseMapping;
if (simpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
if (contributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
if (coreProperties != 0) fields |= UcdFields.CoreProperties;
if (CharacterDecompositionMapping.DecompositionMapping != null) fields |= UcdFields.DecompositionMapping;
fields |= (UcdFields)((int)NumericType << 6);
if (BidirectionalMirrored) fields |= UcdFields.BidirectionalMirrored;
if (OldName != null) fields |= UcdFields.OldName;
if (SimpleUpperCaseMapping != null) fields |= UcdFields.SimpleUpperCaseMapping;
if (SimpleLowerCaseMapping != null) fields |= UcdFields.SimpleLowerCaseMapping;
if (SimpleTitleCaseMapping != null) fields |= UcdFields.SimpleTitleCaseMapping;
if (ContributoryProperties != 0) fields |= UcdFields.ContributoryProperties;
if (CoreProperties != 0 || EmojiProperties != 0) fields |= UcdFields.CorePropertiesAndEmojiProperties;
if (crossRerefences.Count > 0) fields |= UcdFields.CrossRerefences;
writer.Write((ushort)fields);
writer.WriteCodePoint(codePointRange.FirstCodePoint);
writer.WriteCodePoint(CodePointRange.FirstCodePoint);
if ((fields & UcdFields.CodePointRange) != 0) writer.WriteCodePoint(CodePointRange.LastCodePoint);
if ((fields & UcdFields.Name) != 0)
@@ -200,38 +115,38 @@ namespace System.Unicode.Builder
if (nameAliases.Count > 0)
{
writer.WritePackedLength((byte)(name != null ? 3 : 2), nameAliases.Count);
writer.WritePackedLength((byte)(Name != null ? 3 : 2), nameAliases.Count);
if (name != null)
writer.WriteNamePropertyToFile(name);
if (Name != null)
writer.WriteNamePropertyToFile(Name);
foreach (var nameAlias in nameAliases)
writer.WriteNameAliasToFile(nameAlias);
}
else
{
writer.WriteNamePropertyToFile(name);
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);
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)CanonicalCombiningClass);
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)BidirectionalClass);
if ((fields & UcdFields.DecompositionMapping) != 0)
{
writer.Write((byte)characterDecompositionMapping.DecompositionType);
writer.Write(characterDecompositionMapping.DecompositionMapping);
writer.Write((byte)CharacterDecompositionMapping.DecompositionType);
writer.Write(CharacterDecompositionMapping.DecompositionMapping);
}
if ((fields & UcdFields.NumericNumeric) != 0)
{
writer.Write(numericValue.Numerator);
writer.Write(numericValue.Denominator);
writer.Write(NumericValue.Numerator);
writer.Write(NumericValue.Denominator);
}
if ((fields & UcdFields.OldName) != 0) writer.Write(oldName);
if ((fields & UcdFields.SimpleUpperCaseMapping) != 0) writer.Write(simpleUpperCaseMapping);
if ((fields & UcdFields.SimpleLowerCaseMapping) != 0) writer.Write(simpleLowerCaseMapping);
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.OldName) != 0) writer.Write(OldName);
if ((fields & UcdFields.SimpleUpperCaseMapping) != 0) writer.Write(SimpleUpperCaseMapping);
if ((fields & UcdFields.SimpleLowerCaseMapping) != 0) writer.Write(SimpleLowerCaseMapping);
if ((fields & UcdFields.SimpleTitleCaseMapping) != 0) writer.Write(SimpleTitleCaseMapping);
if ((fields & UcdFields.ContributoryProperties) != 0) writer.Write((int)ContributoryProperties);
if ((fields & UcdFields.CorePropertiesAndEmojiProperties) != 0) writer.WriteUInt24((int)CoreProperties | (int)EmojiProperties << 20);
if ((fields & UcdFields.CrossRerefences) != 0)
{
writer.Write(checked((byte)(crossRerefences.Count - 1)));
@@ -72,7 +72,7 @@ namespace System.Unicode.Builder
{
if (byteBuffer[index++] == '\n')
{
if (index < length && !IsNewLineOrComment(byteBuffer[index]))
if ((index < length || RefillBuffer()) && !IsNewLineOrComment(byteBuffer[index]))
{
hasField = true;
goto Completed;
@@ -4,12 +4,14 @@ using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace System.Unicode.Builder
{
internal class UnicodeDataProcessor
{
public const string ReadMeFileName = "ReadMe.txt";
public const string UnicodeDataFileName = "UnicodeData.txt";
public const string PropListFileName = "PropList.txt";
public const string DerivedCorePropertiesFileName = "DerivedCoreProperties.txt";
@@ -21,6 +23,7 @@ namespace System.Unicode.Builder
public const string UnihanVariantsFileName = "Unihan_Variants.txt";
public const string UnihanNumericValuesFileName = "Unihan_NumericValues.txt";
public const string UnihanIrgSourcesFileName = "Unihan_IRGSources.txt";
public const string EmojiDataFileName = "emoji-data.txt";
private static string ParseSimpleCaseMapping(string mapping)
{
@@ -34,13 +37,14 @@ namespace System.Unicode.Builder
return string.IsNullOrEmpty(s) ? null : s;
}
public static async Task<UnicodeInfoBuilder> BuildDataAsync(IDataSource ucdSource, IDataSource unihanSource)
public static async Task<UnicodeInfoBuilder> BuildDataAsync(IDataSource ucdSource, IDataSource unihanSource, IDataSource emojiSource)
{
var builder = new UnicodeInfoBuilder(new Version(7, 0));
var builder = new UnicodeInfoBuilder(await ReadUnicodeVersionAsync(ucdSource).ConfigureAwait(false));
await ProcessUnicodeDataFile(ucdSource, builder).ConfigureAwait(false);
await ProcessPropListFile(ucdSource, builder).ConfigureAwait(false);
await ProcessDerivedCorePropertiesFile(ucdSource, builder).ConfigureAwait(false);
await ProcessEmojiDataFile(emojiSource, builder).ConfigureAwait(false);
await ProcessCjkRadicalsFile(ucdSource, builder).ConfigureAwait(false);
await ProcessNameAliasesFile(ucdSource, builder).ConfigureAwait(false);
await ProcessNamesListFile(ucdSource, builder).ConfigureAwait(false);
@@ -53,6 +57,24 @@ namespace System.Unicode.Builder
return builder;
}
private static async Task<Version> ReadUnicodeVersionAsync(IDataSource ucdSource)
{
using (var reader = new StreamReader(await ucdSource.OpenDataFileAsync(ReadMeFileName).ConfigureAwait(false), Encoding.UTF8, true))
{
string text = await reader.ReadToEndAsync().ConfigureAwait(false);
var match = Regex.Match(text, @"Version\s+(?<Major>[1-9][0-9]*)\.(?<Minor>[0-9]+)\.(?<Update>[0-9]+)\s+of\s+the\s+Unicode\s+Standard\.");
if (!match.Success)
{
match = Regex.Match(text, @"Unicode\s+(?<Major>[1-9][0-9]*)\.(?<Minor>[0-9]+)\.(?<Update>[0-9]+)\.");
}
if (!match.Success) throw new InvalidDataException("Could not determine the version of the Unicode standard defined in the files.");
return new Version(int.Parse(match.Groups["Major"].Value), int.Parse(match.Groups["Minor"].Value), int.Parse(match.Groups["Update"].Value));
}
}
private static async Task ProcessUnicodeDataFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
{
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(UnicodeDataFileName).ConfigureAwait(false), ';'))
@@ -81,11 +103,11 @@ namespace System.Unicode.Builder
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;
}
else if (name == "<control>") // Ignore the name of the property for these code points, as it should really be empty by the spec.
else if (name == "<control>") // Ignore the name of the property for these code points, as it should really be empty by the spec.
{
// For control characters, we can derive a character label in of the form <control-NNNN>, which is not the character name.
name = null;
@@ -108,8 +130,7 @@ namespace System.Unicode.Builder
CanonicalCombiningClass = (CanonicalCombiningClass)byte.Parse(reader.ReadField()),
};
BidirectionalClass bidirectionalClass;
if (EnumHelper<BidirectionalClass>.TryGetNamedValue(reader.ReadField(), out bidirectionalClass))
if (EnumHelper<BidirectionalClass>.TryGetNamedValue(reader.ReadField(), out var bidirectionalClass))
{
characterData.BidirectionalClass = bidirectionalClass;
}
@@ -176,10 +197,8 @@ namespace System.Unicode.Builder
{
while (reader.MoveToNextLine())
{
ContributoryProperties property;
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out var property))
{
builder.SetProperties(property, range);
}
@@ -193,10 +212,23 @@ namespace System.Unicode.Builder
{
while (reader.MoveToNextLine())
{
CoreProperties property;
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out var property))
{
builder.SetProperties(property, range);
}
}
}
}
private static async Task ProcessEmojiDataFile(IDataSource emojiSource, UnicodeInfoBuilder builder)
{
using (var reader = new UnicodeDataFileReader(await emojiSource.OpenDataFileAsync(EmojiDataFileName).ConfigureAwait(false), ';'))
{
while (reader.MoveToNextLine())
{
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
if (EnumHelper<EmojiProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out var property))
{
builder.SetProperties(property, range);
}
@@ -228,7 +260,7 @@ namespace System.Unicode.Builder
if (isSimplified)
{
builder.SetRadicalInfo(radicalIndex, UpdateRadicalData(builder.GetRadicalInfo(radicalIndex), radicalCodePoint, characterCodePoint));
}
}
else
{
builder.SetRadicalInfo(radicalIndex, new CjkRadicalData(radicalCodePoint, characterCodePoint));
@@ -261,9 +293,8 @@ namespace System.Unicode.Builder
string name = reader.ReadField();
string kindName = reader.ReadField();
UnicodeNameAliasKind kind;
if (!EnumHelper<UnicodeNameAliasKind>.TryGetNamedValue(kindName, out kind))
if (!EnumHelper<UnicodeNameAliasKind>.TryGetNamedValue(kindName, out var kind))
throw new InvalidDataException("Unrecognized name alias: " + kindName + ".3");
ucd.NameAliases.Add(new UnicodeNameAlias(name, kind));
@@ -502,7 +533,7 @@ namespace System.Unicode.Builder
var entry = builder.GetUnihan(reader.CodePoint);
var values = reader.PropertyValue.Split(' ');
foreach (var value in values)
foreach (var value in values)
{
bool isSimplified = false;
int index;
@@ -521,8 +552,8 @@ namespace System.Unicode.Builder
}
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));
SeparatorFound:;
entry.UnicodeRadicalStrokeCounts.Add(new UnicodeRadicalStrokeCount(byte.Parse(value.Substring(0, index), NumberStyles.None), sbyte.Parse(value.Substring(index + (isSimplified ? 2 : 1)), NumberStyles.AllowLeadingSign), isSimplified));
}
break;
default:
@@ -9,7 +9,7 @@ namespace System.Unicode.Builder
{
internal class UnicodeInfoBuilder
{
public const int CjkRadicalCount = 214; // The number of radicals (214) shouldn't change in the near future…
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];
@@ -120,7 +120,7 @@ namespace System.Unicode.Builder
if (insertionPoint < 0) throw new InvalidOperationException("The specified range overlaps with pre-existing ranges.");
if (insertionPoint >= ucdEntries.Length)
if (ucdEntryCount == ucdEntries.Length)
{
Array.Resize(ref ucdEntries, ucdEntries.Length << 1);
}
@@ -140,7 +140,7 @@ namespace System.Unicode.Builder
if (insertionPoint < 0) throw new InvalidOperationException("The specified range overlaps with pre-existing ranges.");
if (insertionPoint >= unihanEntries.Length)
if (unihanEntryCount == unihanEntries.Length)
{
Array.Resize(ref unihanEntries, unihanEntries.Length << 1);
}
@@ -195,7 +195,7 @@ namespace System.Unicode.Builder
|| ucdEntries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
|| ucdEntries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException();
throw new InvalidOperationException("Unable to find code point for setting contributory property.");
}
int i = firstIndex;
@@ -226,7 +226,7 @@ namespace System.Unicode.Builder
|| ucdEntries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
|| ucdEntries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException();
throw new InvalidOperationException("Unable to find code point for setting core property.");
}
int i = firstIndex;
@@ -241,6 +241,37 @@ namespace System.Unicode.Builder
}
}
public void SetProperties(EmojiProperties property, UnicodeCodePointRange codePointRange)
{
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
if (firstIndex < 0 && lastIndex < 0)
{
Insert(new UnicodeCharacterDataBuilder(codePointRange) { EmojiProperties = property });
return;
}
if (firstIndex < 0
|| lastIndex < 0
|| ucdEntries[firstIndex].CodePointRange.FirstCodePoint < codePointRange.FirstCodePoint
|| ucdEntries[lastIndex].CodePointRange.LastCodePoint > codePointRange.LastCodePoint)
{
throw new InvalidOperationException("Unable to find code point for setting emoji property.");
}
int i = firstIndex;
while (true)
{
ucdEntries[i].EmojiProperties |= property;
if (i == lastIndex) break;
++i;
}
}
public void SetRadicalInfo(int radicalIndex, CjkRadicalData data)
{
if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex));
@@ -286,16 +317,17 @@ namespace System.Unicode.Builder
{
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
{
writer.Write(new byte[] { (byte)'U', (byte)'C', (byte)'D', 1 });
writer.Write((ushort)7); // Hardcode Unicode 7.0
writer.Write((byte)0);
writer.Write(new byte[] { (byte)'U', (byte)'C', (byte)'D', 2 });
writer.Write(checked((ushort)unicodeVersion.Major));
writer.Write(checked((byte)unicodeVersion.Minor));
writer.Write(checked((byte)unicodeVersion.Build));
writer.WriteCodePoint(ucdEntryCount);
for (int i = 0; i < ucdEntryCount; ++i)
{
ucdEntries[i].WriteToFile(writer);
}
if (blockEntries.Count > 255) throw new InvalidOperationException("There are too many block entries. The file format needs to be upgraded.");
writer.Write((byte)blockEntries.Count);
if (blockEntries.Count > ushort.MaxValue) throw new InvalidOperationException("There are too many block entries. The file format needs to be upgraded.");
writer.Write((ushort)blockEntries.Count);
for (int i = 0; i < blockEntries.Count; ++i)
{
WriteUnicodeBlockToFile(writer, blockEntries[i]);
@@ -1,110 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<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')" />
<Project Sdk="Microsoft.Net.Sdk">
<Import Project="../Common.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{8DFDEE6C-4F0D-4DE1-B346-574CB56D2B8B}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>System.Unicode.Builder</RootNamespace>
<AssemblyName>UnicodeInformation.Builder</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\System.Unicode.snk</AssemblyOriginatorKeyFile>
<AssemblyTitle>UnicodeInformation.Builder</AssemblyTitle>
<Description>Data file builder for the .NET Unicode Information Library.</Description>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<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>
<DependentUpon>UnihanProperty.tt</DependentUpon>
</Compile>
<Compile Include="HexCodePoint.cs" />
<Compile Include="UnihanCharacterDataBuilder.cs" />
<Compile Include="UnihanDataFileReader.cs" />
<Compile Include="Utf8Buffer.cs" />
<Compile Include="CharacterDecompositionMapping.cs" />
<Compile Include="FileDataSource.cs" />
<Compile Include="HttpDataSource.cs" />
<Compile Include="IDataSource.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UnicodeCharacterDataBuilder.cs" />
<Compile Include="UnicodeInfoBuilder.cs" />
<Compile Include="UnicodeDataFileReader.cs" />
<Compile Include="UnicodeDataProcessor.cs" />
<Compile Include="ZipDataSource.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\System.Unicode.snk">
<Link>System.Unicode.snk</Link>
</None>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UnicodeInformation\UnicodeInformation.csproj">
<Project>{cb722958-a1c4-4121-804b-7d5a671491b1}</Project>
<Name>UnicodeInformation</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Content Include="UnihanProperty.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>UnihanProperty.cs</LastGenOutput>
</Content>
<ProjectReference Include="..\UnicodeInformation\UnicodeInformation.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
</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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<Compile Update="UnihanProperty.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>UnihanProperty.tt</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Update="UnihanProperty.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>UnihanProperty.cs</LastGenOutput>
</None>
</ItemGroup>
</Project>
@@ -103,7 +103,7 @@ namespace System.Unicode.Builder
foreach (var radicalStrokeCount in unicodeRadicalStrokeCounts)
{
writer.Write(radicalStrokeCount.Radical);
writer.Write((byte)(radicalStrokeCount.StrokeCount | (radicalStrokeCount.IsSimplified ? 0x80 : 0)));
writer.Write(radicalStrokeCount.RawStrokeCount);
}
}
Binary file not shown.
-30
View File
@@ -1,30 +0,0 @@
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 + ".");
}
}
}
@@ -0,0 +1,80 @@
using System;
using System.Unicode;
using System.Collections.Generic;
using Xunit;
using System.Collections;
using System.Linq;
namespace UnicodeInformation.Tests
{
public class CodePointEnumerableTests
{
public static readonly TheoryData<int[], string> EnumerationTestData = new TheoryData<int[], string>
{
{ new int[0], "" },
{ new int[] { 0x0041,0x1F600, 0x00E9 }, "\u0041\U0001F600\u00E9" },
};
[Theory]
[MemberData(nameof(EnumerationTestData))]
public void EnumerationShouldHaveExpectedResults(int[] expectedCharacters, string text)
{
var enumerable = text.AsCodePointEnumerable();
// Test C# foreach enumeration
{
int i = 0;
foreach (int codePoint in enumerable)
{
Assert.Equal(expectedCharacters[i++], codePoint);
}
Assert.Equal(expectedCharacters.Length, i);
}
// Test generic enumerable
Assert.Equal(expectedCharacters, from codePoint in enumerable select codePoint);
// Test legacy enumeration
{
// We could use Enumerable.Cast<>, but we can't guarantee that the LINQ implementation we use wouldn't be smart and cast IEnumerable back to IEnumerable<int>
var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator();
int index = 0;
while (legacyEnumerator.MoveNext())
{
Assert.True(index < expectedCharacters.Length);
Assert.Equal(expectedCharacters[index++], Assert.IsType<int>(legacyEnumerator.Current));
}
Assert.Equal(expectedCharacters.Length, index);
}
}
[Fact]
public void NullArgumentShouldThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => { foreach (int codePoint in (null as string).AsCodePointEnumerable()) { } });
}
public static readonly TheoryData<XUnitSerializableString> EnumerationFailureTestData = new TheoryData<XUnitSerializableString>
{
"\uDA00",
"\uDCD0",
"\uDCD0\uDA00",
"\u0041\uDA00",
"\u0041\uDCD0",
"\uDA00\u0041",
"\uDCD0\u0041",
"\uDA00\u0041\uDCD0\u0041",
"\u0041\uDA00\u0041\uDCD0\u0041",
};
[Theory]
[MemberData(nameof(EnumerationFailureTestData))]
public void EnumerationOfInvalidUtf16StringsShouldThrowArgumentException(XUnitSerializableString text)
{
Assert.Throws<ArgumentException>(() => { foreach (int codePoint in ((string)text).AsCodePointEnumerable()) { } });
}
}
}
@@ -0,0 +1,69 @@
using System;
using System.Unicode;
using System.Collections.Generic;
using Xunit;
using System.Collections;
using System.Linq;
namespace UnicodeInformation.Tests
{
public class PermissiveCodePointEnumerableTests
{
public static readonly TheoryData<int[], XUnitSerializableString> EnumerationTestData = new TheoryData<int[], XUnitSerializableString>
{
{ new int[0], "" },
{ new int[] { 0xDA00 }, "\uDA00" },
{ new int[] { 0xDCD0 }, "\uDCD0" },
{ new int[] { 0xDCD0, 0xDA00 }, "\uDCD0\uDA00" },
{ new int[] { 0x0041, 0xDA00 }, "\u0041\uDA00" },
{ new int[] { 0x0041, 0xDCD0 }, "\u0041\uDCD0" },
{ new int[] { 0xDA00, 0x0041 }, "\uDA00\u0041" },
{ new int[] { 0xDCD0, 0x0041 }, "\uDCD0\u0041" },
{ new int[] { 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\uDA00\u0041\uDCD0\u0041" },
{ new int[] { 0x0041, 0xDA00, 0x0041, 0xDCD0, 0x0041 }, "\u0041\uDA00\u0041\uDCD0\u0041" },
{ new int[] { 0x0041, 0x1F600, 0x00E9 }, "\u0041\U0001F600\u00E9" },
};
[Theory]
[MemberData(nameof(EnumerationTestData))]
public void EnumerationShouldHaveExpectedResults(int[] expectedCharacters, XUnitSerializableString text)
{
var enumerable = ((string)text).AsPermissiveCodePointEnumerable();
// Test C# foreach enumeration
{
int i = 0;
foreach (int codePoint in enumerable)
{
Assert.Equal(expectedCharacters[i++], codePoint);
}
Assert.Equal(expectedCharacters.Length, i);
}
// Test generic enumerable
Assert.Equal(expectedCharacters, from codePoint in enumerable select codePoint);
// Test legacy enumeration
{
// We could use Enumerable.Cast<>, but we can't guarantee that the LINQ implementation we use wouldn't be smart and cast IEnumerable back to IEnumerable<int>
var legacyEnumerator = ((IEnumerable)enumerable).GetEnumerator();
int index = 0;
while (legacyEnumerator.MoveNext())
{
Assert.True(index < expectedCharacters.Length);
Assert.Equal(expectedCharacters[index++], Assert.IsType<int>(legacyEnumerator.Current));
}
Assert.Equal(expectedCharacters.Length, index);
}
}
[Fact]
public void NullArgumentShouldThrowArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => { foreach (int c in (null as string).AsPermissiveCodePointEnumerable()) { } });
}
}
}
@@ -1,8 +0,0 @@
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("UnicodeInformation.Tests")]
[assembly: AssemblyDescription("")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: Guid("50337426-e884-4394-9e1a-f6f7a555f5d9")]
@@ -0,0 +1,84 @@
using System;
using System.Collections;
using System.Unicode;
using Xunit;
namespace UnicodeInformation.Tests
{
public class UnicodeCodePointRangeTests
{
[Theory]
[InlineData(0, 0x10FFFF)]
public void MultiCodePointRangeShouldHaveExpectedResults(int firstCodePoint, int lastCodePoint)
{
var range = new UnicodeCodePointRange(firstCodePoint, lastCodePoint);
Assert.Equal(firstCodePoint, range.FirstCodePoint);
Assert.Equal(lastCodePoint, range.LastCodePoint);
Assert.False(range.IsSingleCodePoint);
}
[Theory]
[InlineData((int)'A')]
[InlineData(0x0)]
[InlineData(0x10FFFF)]
public void SingleCodePointRangeShouldHaveExpectedResults(int codePoint)
{
var range = new UnicodeCodePointRange(codePoint);
Assert.Equal(codePoint, range.FirstCodePoint);
Assert.Equal(codePoint, range.LastCodePoint);
Assert.True(range.IsSingleCodePoint);
}
[Theory]
[InlineData(-1)]
[InlineData(0x110000)]
[InlineData(int.MaxValue)]
public void ConstructorShouldFailForInvalidCodePoint(int codePoint)
{
Assert.Throws<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(codePoint));
}
[Theory]
[InlineData(-1, 10)]
[InlineData(10, 0x110000)]
[InlineData(-1, 0x110000)]
public void ConstructorShouldFailForInvalidCodePoints(int firstCodePoint, int lastCodePoint)
{
Assert.Throws<ArgumentOutOfRangeException>(() => new UnicodeCodePointRange(firstCodePoint, lastCodePoint));
}
[Theory]
[InlineData(0xA3F, 0x105F)]
public void EnumerationShouldHaveExpectedResults(int firstCodePoint, int lastCodePoint)
{
// Generic test
{
int i = firstCodePoint;
foreach (int n in new UnicodeCodePointRange(firstCodePoint, lastCodePoint))
{
Assert.Equal(i++, n);
}
}
// Nongeneric test
{
int i = firstCodePoint;
var enumerator = (IEnumerator)new UnicodeCodePointRange(firstCodePoint, lastCodePoint).GetEnumerator();
while (enumerator.MoveNext())
{
Assert.Equal(i++, enumerator.Current);
}
enumerator.Reset();
Assert.True(enumerator.MoveNext());
Assert.Equal(firstCodePoint, enumerator.Current);
}
}
}
}
@@ -1,5 +1,4 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Threading.Tasks;
using System.Net;
using System.IO;
@@ -8,10 +7,11 @@ using System.Unicode.Builder;
using System.Text;
using System.Net.Http;
using System.Collections.Generic;
using Xunit;
using System.Linq;
namespace System.Unicode.Tests
{
[TestClass]
public class UnicodeInfoBuilderTests
{
private sealed class FileHttpResponseHandler : HttpMessageHandler
@@ -57,9 +57,8 @@ namespace System.Unicode.Tests
handler.RegisterFile(uri, path);
}
[TestInitialize]
public void Initialize()
public UnicodeInfoBuilderTests()
{
var httpCacheDirectory = Path.GetFullPath(HttpCacheDirectory);
@@ -67,86 +66,89 @@ namespace System.Unicode.Tests
var handler = new FileHttpResponseHandler();
var ucdTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UcdArchiveName);
var unihanTask = RegisterAndDownloadFile(handler, httpCacheDirectory, HttpDataSource.UnicodeCharacterDataUri, Program.UnihanArchiveName);
var ucdTask = RegisterAndDownloadFile(handler, httpCacheDirectory, Program.UnicodeCharacterDataUri, Program.UcdArchiveName);
var unihanTask = RegisterAndDownloadFile(handler, httpCacheDirectory, Program.UnicodeCharacterDataUri, Program.UnihanArchiveName);
var emojiTasks = Program.emojiRequiredFiles.Select(f => RegisterAndDownloadFile(handler, httpCacheDirectory, Program.EmojiDataUri, f)).ToArray();
Program.HttpMessageHandler = handler;
Program.SetHttpMessageHandler(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);
Task.WaitAll(ucdTask, unihanTask, Task.WhenAll(emojiTasks));
}
[TestMethod]
[Fact]
public void DownloadUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, false, false))
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, false, false).Result)
{
}
}
[TestMethod]
[Fact]
public void DownloadAndSaveUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, false))
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, false).Result)
{
}
}
[TestMethod]
[Fact]
public void ExtractUcdArchive()
{
using (var source = Program.GetDataSource(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, true))
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, true).Result)
{
}
}
[TestMethod]
[Fact]
public void DownloadUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, false, false))
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, false, false).Result)
{
}
}
[TestMethod]
[Fact]
public void DownloadAndSaveUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, false))
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, false).Result)
{
}
}
[TestMethod]
[Fact]
public void ExtractUnihanArchive()
{
using (var source = Program.GetDataSource(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, true))
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, true).Result)
{
}
}
[TestMethod]
[Fact]
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))
using (var ucdSource = await Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var unihanSource = await Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var emojiSource = new HttpDataSource(Program.EmojiDataUri, Program.HttpClient))
{
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource, emojiSource));
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
Assert.Equal((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
}
}
[TestMethod]
[Fact]
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))
using (var ucdSource = await Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var unihanSource = await Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, null, null, null))
using (var emojiSource = new HttpDataSource(Program.EmojiDataUri, Program.HttpClient))
{
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource));
var data = (await UnicodeDataProcessor.BuildDataAsync(ucdSource, unihanSource, emojiSource));
//using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
using (var stream = File.Create("ucd.dat"))
@@ -157,7 +159,7 @@ namespace System.Unicode.Tests
}
#if DEBUG
[TestMethod]
[Fact]
public void CodePointEncodingTest()
{
using (var stream = new MemoryStream(4))
@@ -169,7 +171,7 @@ namespace System.Unicode.Tests
writer.WriteCodePoint(i);
writer.Flush();
stream.Position = 0;
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
Assert.Equal(i, UnicodeInfo.ReadCodePoint(reader));
stream.Position = 0;
}
}
+149 -232
View File
@@ -1,299 +1,216 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Unicode;
using System.Globalization;
using System.Collections.Generic;
using System.Collections;
using Xunit;
namespace UnicodeInformation.Tests
{
[TestClass]
public class UnicodeInfoTests
{
[TestMethod]
public void CodePointEnumeratorTest()
[Fact]
public void UnicodeVersionShouldBeTheLatestSupported()
{
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());
Assert.Equal(new Version(10, 0, 0), UnicodeInfo.UnicodeVersion);
}
[TestMethod]
public void DisplayTextTest()
[Fact]
public void ControlCharactersShouldHaveSpecificDisplayText()
{
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.Equal(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(i));
Assert.Equal(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)
[Theory]
[InlineData("\u0041", 0x0041)]
[InlineData("\U0001F600", 0x1F600)]
[InlineData("\u00E9", 0x00E9)]
public void DisplayTextShouldReturnExpectedResult(string expectedText, int codePoint)
{
AssertChar(codePoint, category, UnicodeNumericType.None, null, name, block);
}
Assert.Equal(expectedText, UnicodeInfo.GetDisplayText(codePoint));
}
private static void AssertChar(int codePoint, UnicodeCategory category, UnicodeNumericType numericType, UnicodeRationalNumber? numericValue, string name, string block)
[Theory]
[InlineData(0x0030, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, "0", "DIGIT ZERO", "Basic Latin")]
[InlineData(0x0031, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, "1", "DIGIT ONE", "Basic Latin")]
[InlineData(0x0032, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, "2", "DIGIT TWO", "Basic Latin")]
[InlineData(0x0035, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, "5", "DIGIT FIVE", "Basic Latin")]
[InlineData(0x0039, UnicodeCategory.DecimalDigitNumber, UnicodeNumericType.Decimal, "9", "DIGIT NINE", "Basic Latin")]
[InlineData(0x0041, UnicodeCategory.UppercaseLetter, UnicodeNumericType.None, null, "LATIN CAPITAL LETTER A", "Basic Latin")]
[InlineData(0x1F600, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "GRINNING FACE", "Emoticons")]
[InlineData(0x00E9, UnicodeCategory.LowercaseLetter, UnicodeNumericType.None, null, "LATIN SMALL LETTER E WITH ACUTE", "Latin-1 Supplement")]
[InlineData(0xD4DB, UnicodeCategory.OtherLetter, UnicodeNumericType.None, null, "HANGUL SYLLABLE PWILH", "Hangul Syllables")]
[InlineData(0x1F574, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "MAN IN BUSINESS SUIT LEVITATING", "Miscellaneous Symbols and Pictographs")]
[InlineData(0x16FE0, UnicodeCategory.ModifierLetter, UnicodeNumericType.None, null, "TANGUT ITERATION MARK", "Ideographic Symbols and Punctuation")]
[InlineData(0x17000, UnicodeCategory.OtherLetter, UnicodeNumericType.None, null, "TANGUT IDEOGRAPH-17000", "Tangut")]
[InlineData(0x17943, UnicodeCategory.OtherLetter, UnicodeNumericType.None, null, "TANGUT IDEOGRAPH-17943", "Tangut")] // Number 4
[InlineData(0x187EC, UnicodeCategory.OtherLetter, UnicodeNumericType.None, null, "TANGUT IDEOGRAPH-187EC", "Tangut")]
[InlineData(0x0D76, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "1/16", "MALAYALAM FRACTION ONE SIXTEENTH", "Malayalam")]
[InlineData(0x0D5D, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "3/20", "MALAYALAM FRACTION THREE TWENTIETHS", "Malayalam")]
[InlineData(0x0D59, UnicodeCategory.OtherNumber, UnicodeNumericType.Numeric, "1/40", "MALAYALAM FRACTION ONE FORTIETH", "Malayalam")]
[InlineData(0x1F953, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BACON", "Supplemental Symbols and Pictographs")]
[InlineData(0x1F966, UnicodeCategory.OtherSymbol, UnicodeNumericType.None, null, "BROCCOLI", "Supplemental Symbols and Pictographs")]
public void CharacterInfoShouldHaveExpectedResults(int codePoint, UnicodeCategory expectedCategory, UnicodeNumericType expectedNumericType, string expectedNumericValue, string expectedName, string expectedBlock)
{
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);
Assert.Equal(codePoint, info.CodePoint);
Assert.Equal(expectedCategory, info.Category);
Assert.Equal(expectedNumericType, info.NumericType);
if (expectedNumericValue != null) Assert.Equal(UnicodeRationalNumber.Parse(expectedNumericValue), info.NumericValue);
else Assert.Null(info.NumericValue);
Assert.Equal(expectedName, info.Name);
Assert.Equal(expectedBlock, UnicodeInfo.GetBlockName(codePoint));
Assert.Equal(expectedBlock, 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()
[Theory]
[InlineData('\0')]
[InlineData('\uABFF')]
[InlineData('\uD7A5')]
public void HangulNameShouldFailForNonHangulCodePoints(char codePoint)
{
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));
Assert.Throws<ArgumentOutOfRangeException>(() => HangulInfo.GetHangulName(codePoint));
}
#endif
[Theory]
[InlineData("HANGUL SYLLABLE PWILH", 0xD4DB)]
[InlineData("HANGUL SYLLABLE PWAENG", 0xD439)]
[InlineData("HANGUL SYLLABLE PANJ", 0xD311)]
[InlineData("HANGUL SYLLABLE TOLM", 0xD1AA)]
public void HangulNameShouldReturnExpectedResult(string expectedName, int codePoint)
{
Assert.Equal(expectedName, UnicodeInfo.GetName(codePoint));
}
[TestMethod]
public void RadicalStrokeCountTest()
[Theory]
[InlineData("Basic Latin", 0x0041)]
[InlineData("Miscellaneous Technical", 0x2307)]
[InlineData("Hangul Syllables", 0xD311)]
[InlineData("Miscellaneous Symbols and Pictographs", 0x1F574)]
public void MethodGetBlockNameShouldHaveExpectedResult(string expectedBlockName, int codePoint)
{
Assert.Equal(expectedBlockName, UnicodeInfo.GetBlockName(codePoint));
}
[Fact]
public void RadicalStrokeCountShouldHaveExpectedResults()
{
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);
Assert.NotEmpty(char5E7A.UnicodeRadicalStrokeCounts);
Assert.False(char5E7A.UnicodeRadicalStrokeCounts[0].IsSimplified);
Assert.Equal(52, char5E7A.UnicodeRadicalStrokeCounts[0].Radical);
Assert.Equal(0, char5E7A.UnicodeRadicalStrokeCounts[0].StrokeCount);
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);
Assert.NotEmpty(char2A6D6.UnicodeRadicalStrokeCounts);
Assert.False(char2A6D6.UnicodeRadicalStrokeCounts[0].IsSimplified);
Assert.Equal(214, char2A6D6.UnicodeRadicalStrokeCounts[0].Radical);
Assert.Equal(20, char2A6D6.UnicodeRadicalStrokeCounts[0].StrokeCount);
}
[TestMethod]
public void RadicalInfoTest()
[Fact]
public void RadicalInfoShouldHaveExpectedResults()
{
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);
Assert.False(radical1.HasSimplifiedForm);
Assert.Equal(1, radical1.RadicalIndex);
Assert.Equal('\u2F00', radical1.TraditionalRadicalCodePoint);
Assert.Equal('\u4E00', radical1.TraditionalCharacterCodePoint);
Assert.Equal('\u2F00', radical1.SimplifiedRadicalCodePoint);
Assert.Equal('\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);
Assert.False(radical214.HasSimplifiedForm);
Assert.Equal(214, radical214.RadicalIndex);
Assert.Equal('\u2FD5', radical214.TraditionalRadicalCodePoint);
Assert.Equal('\u9FA0', radical214.TraditionalCharacterCodePoint);
Assert.Equal('\u2FD5', radical214.SimplifiedRadicalCodePoint);
Assert.Equal('\u9FA0', radical214.SimplifiedCharacterCodePoint);
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(0), nameof(UnicodeInfo.GetCjkRadicalInfo));
AssertEx.ThrowsExactly<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(215), nameof(UnicodeInfo.GetCjkRadicalInfo));
Assert.Throws<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(0));
Assert.Throws<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(215));
}
[TestMethod]
public void CodePointRangeTest()
[Fact]
public void MethodGetNameShouldNeverFail()
{
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
for (int i = 0; i <= 0x10FFFF; i++)
{
int i = start;
foreach (int n in new UnicodeCodePointRange(start, end))
{
Assert.AreEqual(i++, n);
}
UnicodeInfo.GetName(i);
}
}
// Nongeneric test
[Fact]
public void MethodGetDisplayTextShouldNeverFail()
{
for (int i = 0; i <= 0x10FFFF; i++)
{
int i = start;
UnicodeInfo.GetDisplayText(i);
}
}
var enumerator = (IEnumerator)new UnicodeCodePointRange(start, end).GetEnumerator();
[Fact]
public void MethodGetCategoryShouldNeverFail()
{
for (int i = 0; i <= 0x10FFFF; i++)
{
UnicodeInfo.GetCategory(i);
}
}
while (enumerator.MoveNext())
{
Assert.AreEqual(i++, enumerator.Current);
}
[Fact]
public void MethodGetCharInfoShouldNeverFail()
{
for (int i = 0; i <= 0x10FFFF; i++)
{
UnicodeInfo.GetCharInfo(i);
}
}
enumerator.Reset();
[Fact]
public void MethodGetCharInfoShouldHaveCoherentResults()
{
for (int i = 0; i <= 0x10FFFF; i++)
{
var charInfo = UnicodeInfo.GetCharInfo(i);
Assert.AreEqual(true, enumerator.MoveNext());
Assert.AreEqual(start, enumerator.Current);
Assert.Equal(charInfo.Name, UnicodeInfo.GetName(i));
Assert.Equal(charInfo.Category, UnicodeInfo.GetCategory(i));
Assert.Equal(UnicodeInfo.GetDisplayText(charInfo), UnicodeInfo.GetDisplayText(i));
}
}
#if DEBUG
[TestMethod]
public void UnihanCodePointPackingTest()
[Fact]
public void UnihanCodePointPackingShouldHaveExpectedResults()
{
for (int i = 0x3400; i < 0x4E00; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x4E00; i < 0xA000; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0xF900; i < 0xFB00; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x20000; i < 0x2F800; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
for (int i = 0x2F800; i < 0x30000; ++i)
Assert.AreEqual(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
Assert.Equal(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.";
// The PackCodePoint method should fail for code points outside of the valid range.
Assert.Throws<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xA000));
Assert.Throws<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0xFB00));
Assert.Throws<ArgumentOutOfRangeException>(() => UnihanCharacterData.PackCodePoint(0x30000));
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);
// The UnpackCodePoint method should fail for values outside of the valid range.
Assert.Throws<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(-1));
Assert.Throws<ArgumentOutOfRangeException>(() => UnihanCharacterData.UnpackCodePoint(0x20000));
}
#endif
}
@@ -1,113 +1,27 @@
<?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)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{50337426-E884-4394-9E1A-F6F7A555F5D9}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>UnicodeInformation.Tests</RootNamespace>
<AssemblyName>UnicodeInformation.Tests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<Project Sdk="Microsoft.Net.Sdk">
<Import Project="../Common.props" />
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\System.Unicode.snk</AssemblyOriginatorKeyFile>
<Description />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.WebRequest" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<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">
<Project>{8dfdee6c-4f0d-4de1-b346-574cb56d2b8b}</Project>
<Name>UnicodeInformation.Builder</Name>
</ProjectReference>
<ProjectReference Include="..\UnicodeInformation\UnicodeInformation.csproj">
<Project>{cb722958-a1c4-4121-804b-7d5a671491b1}</Project>
<Name>UnicodeInformation</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="..\System.Unicode.snk">
<Link>System.Unicode.snk</Link>
</None>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta3-build3705" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\UnicodeInformation\UnicodeInformation.csproj" />
<ProjectReference Include="..\UnicodeInformation.Builder\UnicodeInformation.Builder.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Unicode;
using Xunit;
namespace UnicodeInformation.Tests
{
public class UnicodeRationalNumerTests
{
[Fact]
public void DefaultValueShouldBeDetectedAsSuch()
{
Assert.True(default(UnicodeRationalNumber).IsDefaultValue);
Assert.Equal(string.Empty, default(UnicodeRationalNumber).ToString());
}
public static readonly TheoryData<long> Numerators = new TheoryData<long>
{
0,
1,
long.MaxValue,
long.MinValue
};
[Theory]
[MemberData(nameof(Numerators))]
public void NumbersAndFractionOverOneShouldBeEqual(long numerator)
{
Assert.Equal(new UnicodeRationalNumber(numerator), new UnicodeRationalNumber(numerator, 1));
Assert.Equal(new UnicodeRationalNumber(numerator).GetHashCode(), new UnicodeRationalNumber(numerator, 1).GetHashCode());
}
[Theory]
[InlineData("1/10", "10/1")]
[InlineData("2/10", "1/10")]
[InlineData("1/20", "1/10")]
[InlineData("2/2", "1/1")]
[InlineData("2/1", "1/2")]
public void DifferentRationalNumbersShouldNotBeDeterminedEqual(string number1, string number2)
{
Assert.NotEqual(UnicodeRationalNumber.Parse(number1), UnicodeRationalNumber.Parse(number2));
Assert.NotEqual(UnicodeRationalNumber.Parse(number2), UnicodeRationalNumber.Parse(number1));
}
public static readonly TheoryData<string, long, byte> StringConversionTestData = new TheoryData<string, long, byte>
{
{ "0", 0, 1 },
{ "1", 1, 1 },
{ "1/100", 1, 100 },
{ "-20/7", -20, 7 },
{ "-5", -5, 1 },
{ "-9223372036854775808", long.MinValue, 1 },
{ "9223372036854775807", long.MaxValue, 1 },
{ "9223372036854775807/255", long.MaxValue, byte.MaxValue },
};
[Theory]
[MemberData(nameof(StringConversionTestData))]
public void MethodToStringShouldReturnExpectedResult(string expectedText, long numerator, byte denominator)
{
Assert.Equal(expectedText, new UnicodeRationalNumber(numerator, denominator).ToString());
}
[Fact]
public void ParsingNullValueShoudlFail()
{
Assert.Throws<ArgumentNullException>(() => UnicodeRationalNumber.Parse(null));
}
[Fact]
public void ParsingEmptyValueShoudlFail()
{
Assert.Throws<ArgumentException>(() => UnicodeRationalNumber.Parse(string.Empty));
}
[Theory]
[InlineData(0, "0")]
[InlineData(0, "0/1")]
[InlineData(1, "1")]
[InlineData(1, "1/1")]
[InlineData(long.MaxValue, "9223372036854775807")]
[InlineData(long.MaxValue, "9223372036854775807/1")]
[InlineData(long.MinValue, "-9223372036854775808")]
[InlineData(long.MinValue, "-9223372036854775808/1")]
public void ParsingCanReturnSimpleNumber(long expectedNumber, string text)
{
Assert.Equal(new UnicodeRationalNumber(expectedNumber), UnicodeRationalNumber.Parse(text));
}
public static readonly TheoryData<long, byte, string> FractionParsingTestData = new TheoryData<long, byte, string>
{
{ 0, 1, "0" },
{ 0, 1, "0/1" },
{ 1, 1, "1" },
{ 1, 1, "1/1" },
{ 1, 10, "1/10" },
{ 1, 255, "1/255" },
{ 3, 4, "3/4" },
{ 6, 8, "6/8" },
{ 1, 255, "1/255" },
{ long.MaxValue, 1, "9223372036854775807" },
{ long.MaxValue, 1, "9223372036854775807/1" },
{ long.MinValue, 1, "-9223372036854775808" },
{ long.MinValue, 1, "-9223372036854775808/1" },
{ long.MaxValue, byte.MaxValue, "9223372036854775807/255" },
};
[Theory]
[MemberData(nameof(FractionParsingTestData))]
public void ParsingCanReturnFraction(long expectedNumerator, byte expectedDenominator, string text)
{
Assert.Equal(new UnicodeRationalNumber(expectedNumerator, expectedDenominator), UnicodeRationalNumber.Parse(text));
}
[Fact]
public void EqualityComparisonAndHashCodeShouldWorkAsExpected()
{
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.True(hashSet.Add(number));
// Verify that all numbers are already in the list
foreach (var number in numbers)
Assert.False(hashSet.Add(number));
}
}
}
@@ -0,0 +1,62 @@
using System;
using System.Unicode;
using System.Globalization;
using System.Collections.Generic;
using System.Collections;
using Xunit;
using System.Linq;
using Xunit.Abstractions;
using System.Text;
namespace UnicodeInformation.Tests
{
// This class is needed because apparently, somewhere in the process of unit testing, strings with invalid UTF-16 sequences are "fixed", which totally messes up the tests here.
// This is just a wrapper over regular strings… Data is serialized as an array of chars instead of a string. This seems to do the trick.
public class XUnitSerializableString : IEquatable<XUnitSerializableString>, IXunitSerializable
{
private string value;
public XUnitSerializableString() : this(null) { }
public XUnitSerializableString(string value)
{
this.value = value;
}
void IXunitSerializable.Deserialize(IXunitSerializationInfo info)
{
var chars = info.GetValue<char[]>("Chars");
value = chars != null ?
new string(chars) :
null;
}
void IXunitSerializable.Serialize(IXunitSerializationInfo info)
{
info.AddValue("Chars", value?.ToCharArray(), typeof(char[]));
}
public override string ToString()
{
if (string.IsNullOrEmpty(value)) return value;
var sb = new StringBuilder(value.Length * 6);
foreach (char c in value)
{
sb.Append(@"\u")
.Append(((ushort)c).ToString("X4"));
}
return sb.ToString();
}
public bool Equals(XUnitSerializableString other) => value == other.value;
public override bool Equals(object obj) => obj is XUnitSerializableString && Equals((XUnitSerializableString)obj);
public override int GetHashCode() => StringComparer.Ordinal.GetHashCode(value);
public static implicit operator string(XUnitSerializableString text) => text.value;
public static implicit operator XUnitSerializableString(string text) => new XUnitSerializableString(text);
}
}
+10 -5
View File
@@ -1,19 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.22310.1
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeCharacterInspector", "UnicodeCharacterInspector\UnicodeCharacterInspector.csproj", "{04E97F21-EF04-441F-83CF-2E71F3AAB089}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeInformation", "UnicodeInformation\UnicodeInformation.csproj", "{CB722958-A1C4-4121-804B-7D5A671491B1}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnicodeInformation", "UnicodeInformation\UnicodeInformation.csproj", "{CB722958-A1C4-4121-804B-7D5A671491B1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeInformation.Tests", "UnicodeInformation.Tests\UnicodeInformation.Tests.csproj", "{50337426-E884-4394-9E1A-F6F7A555F5D9}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnicodeInformation.Tests", "UnicodeInformation.Tests\UnicodeInformation.Tests.csproj", "{50337426-E884-4394-9E1A-F6F7A555F5D9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeInformation.Builder", "UnicodeInformation.Builder\UnicodeInformation.Builder.csproj", "{8DFDEE6C-4F0D-4DE1-B346-574CB56D2B8B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UnicodeInformation.Builder", "UnicodeInformation.Builder\UnicodeInformation.Builder.csproj", "{8DFDEE6C-4F0D-4DE1-B346-574CB56D2B8B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{73097DF3-04B7-4C5F-B4EA-0EB800E40702}"
ProjectSection(SolutionItems) = preProject
appveyor.yml = appveyor.yml
AssemblyInfo.Common.cs = AssemblyInfo.Common.cs
Common.props = Common.props
Example.cs = Example.cs
LICENSE.txt = LICENSE.txt
README.md = README.md
@@ -51,4 +53,7 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B155A7AA-DB01-4F49-8985-33AC25BC4B98}
EndGlobalSection
EndGlobal
+71 -29
View File
@@ -1,59 +1,101 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace System.Unicode
{
/// <summary>Represents possible values for the Bidi_Class unicode property.</summary>
public enum BidirectionalClass : byte
{
[ValueName("L"), ValueName("Left_To_Right"), Display(Name = "Left_To_Right", Description = "any strong left-to-right character")]
/// <summary>Represents the value Left_To_Right.</summary>
/// <remarks>Any strong left-to-right character.</remarks>
[ValueName("L"), ValueName("Left_To_Right"), Display(Name = "Left_To_Right", Description = "Any strong left-to-right character.")]
LeftToRight,
[ValueName("R"), ValueName("Right_To_Left"), Display(Name = "Right_To_Left", Description = "any strong right-to-left (non-Arabic-type) character")]
/// <summary>Represents the value Right_To_Left.</summary>
/// <remarks>Any strong right-to-left (non-Arabic-type) character.</remarks>
[ValueName("R"), ValueName("Right_To_Left"), Display(Name = "Right_To_Left", Description = "Any strong right-to-left (non-Arabic-type) character.")]
RightToLeft,
[ValueName("AL"), ValueName("Arabic_Letter"), Display(Name = "Arabic_Letter", Description = "any strong right-to-left (Arabic-type) character")]
/// <summary>Represents the value Arabic_Letter.</summary>
/// <remarks>Any strong right-to-left (Arabic-type) character.</remarks>
[ValueName("AL"), ValueName("Arabic_Letter"), Display(Name = "Arabic_Letter", Description = "Any strong right-to-left (Arabic-type) character.")]
ArabicLetter,
[ValueName("EN"), ValueName("European_Number"), Display(Name = "European_Number", Description = "any ASCII digit or Eastern Arabic-Indic digit")]
/// <summary>Represents the value European_Number.</summary>
/// <remarks>Any ASCII digit or Eastern Arabic-Indic digit.</remarks>
[ValueName("EN"), ValueName("European_Number"), Display(Name = "European_Number", Description = "Any ASCII digit or Eastern Arabic-Indic digit.")]
EuropeanNumber,
[ValueName("ES"), ValueName("European_Separator"), Display(Name = "European_Separator", Description = "plus and minus signs")]
/// <summary>Represents the value European_Separator.</summary>
/// <remarks>Plus and minus signs.</remarks>
[ValueName("ES"), ValueName("European_Separator"), Display(Name = "European_Separator", Description = "Plus and minus signs.")]
EuropeanSeparator,
[ValueName("ET"), ValueName("European_Terminator"), Display(Name = "European_Terminator", Description = "a terminator in a numeric format context, includes currency signs")]
/// <summary>Represents the value European_Terminator.</summary>
/// <remarks>A terminator in a numeric format context, includes currency signs.</remarks>
[ValueName("ET"), ValueName("European_Terminator"), Display(Name = "European_Terminator", Description = "A terminator in a numeric format context, includes currency signs.")]
EuropeanTerminator,
[ValueName("AN"), ValueName("Arabic_Number"), Display(Name = "Arabic_Number", Description = "any Arabic-Indic digit")]
/// <summary>Represents the value Arabic_Number.</summary>
/// <remarks>Any Arabic-Indic digit.</remarks>
[ValueName("AN"), ValueName("Arabic_Number"), Display(Name = "Arabic_Number", Description = "Any Arabic-Indic digit.")]
ArabicNumber,
[ValueName("CS"), ValueName("Common_Separator"), Display(Name = "Common_Separator", Description = "commas, colons, and slashes")]
/// <summary>Represents the value Common_Separator.</summary>
/// <remarks>Commas, colons, and slashes.</remarks>
[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")]
/// <summary>Represents the value Nonspacing_Mark.</summary>
/// <remarks>Any nonspacing mark.</remarks>
[ValueName("NSM"), ValueName("Nonspacing_Mark"), Display(Name = "Nonspacing_Mark", Description = "Any nonspacing mark.")]
NonSpacingMark,
[ValueName("BN"), ValueName("Boundary_Neutral"), Display(Name = "Boundary_Neutral", Description = "most format characters, control codes, or noncharacters")]
/// <summary>Represents the value Boundary_Neutral.</summary>
/// <remarks>Most format characters, control codes, or noncharacters.</remarks>
[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")]
/// <summary>Represents the value Paragraph_Separator.</summary>
/// <remarks>Various newline characters.</remarks>
[ValueName("B"), ValueName("Paragraph_Separator"), Display(Name = "Paragraph_Separator", Description = "Various newline characters.")]
ParagraphSeparator,
[ValueName("S"), ValueName("Segment_Separator"), Display(Name = "Segment_Separator", Description = "various segment-related control codes")]
/// <summary>Represents the value Segment_Separator.</summary>
/// <remarks>Various segment-related control codes.</remarks>
[ValueName("S"), ValueName("Segment_Separator"), Display(Name = "Segment_Separator", Description = "Various segment-related control codes.")]
SegmentSeparator,
[ValueName("WS"), ValueName("White_Space"), Display(Name = "White_Space", Description = "spaces")]
/// <summary>Represents the value White_Space.</summary>
/// <remarks>Spaces.</remarks>
[ValueName("WS"), ValueName("White_Space"), Display(Name = "White_Space", Description = "Spaces.")]
WhiteSpace,
[ValueName("ON"), ValueName("Other_Neutral"), Display(Name = "Other_Neutral", Description = "most other symbols and punctuation marks")]
/// <summary>Represents the value Other_Neutral.</summary>
/// <remarks>Most other symbols and punctuation marks.</remarks>
[ValueName("ON"), ValueName("Other_Neutral"), Display(Name = "Other_Neutral", Description = "Most other symbols and punctuation marks.")]
OtherNeutral,
[ValueName("LRE"), ValueName("Left_To_Right_Embedding"), Display(Name = "Left_To_Right_Embedding", Description = "U+202A: the LR embedding control")]
/// <summary>Represents the value Left_To_Right_Embedding.</summary>
/// <remarks>U+202A: the LR embedding control.</remarks>
[ValueName("LRE"), ValueName("Left_To_Right_Embedding"), Display(Name = "Left_To_Right_Embedding", Description = "U+202A: the LR embedding control.")]
LeftToRightEmbedding,
[ValueName("LRO"), ValueName("Left_To_Right_Override"), Display(Name = "Left_To_Right_Override", Description = "U+202D: the LR override control")]
/// <summary>Represents the value Left_To_Right_Override.</summary>
/// <remarks>U+202D: the LR override control.</remarks>
[ValueName("LRO"), ValueName("Left_To_Right_Override"), Display(Name = "Left_To_Right_Override", Description = "U+202D: the LR override control.")]
LeftToRightOverride,
[ValueName("RLE"), ValueName("Right_To_Left_Embedding"), Display(Name = "Right_To_Left_Embedding", Description = "U+202B: the RL embedding control")]
/// <summary>Represents the value Right_To_Left_Embedding.</summary>
/// <remarks>U+202B: the RL embedding control.</remarks>
[ValueName("RLE"), ValueName("Right_To_Left_Embedding"), Display(Name = "Right_To_Left_Embedding", Description = "U+202B: the RL embedding control.")]
RightToLeftEmbedding,
[ValueName("RLO"), ValueName("Right_To_Left_Override"), Display(Name = "Right_To_Left_Override", Description = "U+202E: the RL override control")]
/// <summary>Represents the value Right_To_Left_Override.</summary>
/// <remarks>U+202E: the RL override control.</remarks>
[ValueName("RLO"), ValueName("Right_To_Left_Override"), Display(Name = "Right_To_Left_Override", Description = "U+202E: the RL override control.")]
RightToLeftOverride,
[ValueName("PDF"), ValueName("Pop_Directional_Format"), Display(Name = "Pop_Directional_Format", Description = "U+202C: terminates an embedding or override control")]
/// <summary>Represents the value Pop_Directional_Format.</summary>
/// <remarks>U+202C: terminates an embedding or override control.</remarks>
[ValueName("PDF"), ValueName("Pop_Directional_Format"), Display(Name = "Pop_Directional_Format", Description = "U+202C: terminates an embedding or override control.")]
PopDirectionalFormat,
[ValueName("LRI"), ValueName("Left_To_Right_Isolate"), Display(Name = "Left_To_Right_Isolate", Description = "U+2066: the LR isolate control")]
/// <summary>Represents the value Left_To_Right_Isolate.</summary>
/// <remarks>U+2066: the LR isolate control.</remarks>
[ValueName("LRI"), ValueName("Left_To_Right_Isolate"), Display(Name = "Left_To_Right_Isolate", Description = "U+2066: the LR isolate control.")]
LeftToRightIsolate,
[ValueName("RLI"), ValueName("Right_To_Left_Isolate"), Display(Name = "Right_To_Left_Isolate", Description = "U+2067: the RL isolate control")]
/// <summary>Represents the value Right_To_Left_Isolate.</summary>
/// <remarks>U+2067: the RL isolate control.</remarks>
[ValueName("RLI"), ValueName("Right_To_Left_Isolate"), Display(Name = "Right_To_Left_Isolate", Description = "U+2067: the RL isolate control.")]
RightToLeftIsolate,
[ValueName("FSI"), ValueName("First_Strong_Isolate"), Display(Name = "First_Strong_Isolate", Description = "U+2068: the first strong isolate control")]
/// <summary>Represents the value First_Strong_Isolate.</summary>
/// <remarks>U+2068: the first strong isolate control.</remarks>
[ValueName("FSI"), ValueName("First_Strong_Isolate"), Display(Name = "First_Strong_Isolate", Description = "U+2068: the first strong isolate control.")]
FirstStrongIsolate,
[ValueName("PDI"), ValueName("Pop_Directional_Isolate"), Display(Name = "Pop_Directional_Isolate", Description = "U+2069: terminates an isolate control")]
/// <summary>Represents the value Pop_Directional_Isolate.</summary>
/// <remarks>U+2069: terminates an isolate control.</remarks>
[ValueName("PDI"), ValueName("Pop_Directional_Isolate"), Display(Name = "Pop_Directional_Isolate", Description = "U+2069: terminates an isolate control.")]
PopDirectionalIsolate,
}
}
@@ -2,434 +2,649 @@
namespace System.Unicode
{
/// <summary>Represent known values for the Canonical_Combining_Class property.</summary>
public enum CanonicalCombiningClass : byte
{
/// <summary>Represents the value Not_Reordered.</summary>
[ValueName("Not_Reordered"), Display(Name = "Not_Reordered", Description = "Spacing and enclosing marks; also many vowel and consonant signs, even if nonspacing")]
NotReordered = 0,
/// <summary>Represents the value Overlay.</summary>
[ValueName("Overlay"), Display(Name = "Overlay", Description = "Marks which overlay a base letter or symbol")]
Overlay = 1,
/// <summary>Represents the value Nukta.</summary>
[ValueName("Nukta"), Display(Name = "Nukta", Description = "Diacritic nukta marks in Brahmi-derived scripts")]
Nukta = 7,
/// <summary>Represents the value Kana_Voicing.</summary>
[ValueName("Kana_Voicing"), Display(Name = "Kana_Voicing", Description = "Hiragana/Katakana voicing marks")]
KanaVoicing = 8,
/// <summary>Represents the value Virama.</summary>
[ValueName("Virama"), Display(Name = "Virama", Description = "Viramas")]
Virama = 9,
/// <summary>Represents the value Ccc10.</summary>
[ValueName("Ccc10"), Display(Name = "Ccc10", Description = "Start of fixed position classes")]
Ccc10 = 10,
/// <summary>Represents the value Ccc11.</summary>
[ValueName("Ccc11"), Display(Name = "Ccc11")]
Ccc11 = 11,
/// <summary>Represents the value Ccc12.</summary>
[ValueName("Ccc12"), Display(Name = "Ccc12")]
Ccc12 = 12,
/// <summary>Represents the value Ccc13.</summary>
[ValueName("Ccc13"), Display(Name = "Ccc13")]
Ccc13 = 13,
/// <summary>Represents the value Ccc14.</summary>
[ValueName("Ccc14"), Display(Name = "Ccc14")]
Ccc14 = 14,
/// <summary>Represents the value Ccc15.</summary>
[ValueName("Ccc15"), Display(Name = "Ccc15")]
Ccc15 = 15,
/// <summary>Represents the value Ccc16.</summary>
[ValueName("Ccc16"), Display(Name = "Ccc16")]
Ccc16 = 16,
/// <summary>Represents the value Ccc17.</summary>
[ValueName("Ccc17"), Display(Name = "Ccc17")]
Ccc17 = 17,
/// <summary>Represents the value Ccc18.</summary>
[ValueName("Ccc18"), Display(Name = "Ccc18")]
Ccc18 = 18,
/// <summary>Represents the value Ccc19.</summary>
[ValueName("Ccc19"), Display(Name = "Ccc19")]
Ccc19 = 19,
/// <summary>Represents the value Ccc20.</summary>
[ValueName("Ccc20"), Display(Name = "Ccc20")]
Ccc20 = 20,
/// <summary>Represents the value Ccc21.</summary>
[ValueName("Ccc21"), Display(Name = "Ccc21")]
Ccc21 = 21,
/// <summary>Represents the value Ccc22.</summary>
[ValueName("Ccc22"), Display(Name = "Ccc22")]
Ccc22 = 22,
/// <summary>Represents the value Ccc23.</summary>
[ValueName("Ccc23"), Display(Name = "Ccc23")]
Ccc23 = 23,
/// <summary>Represents the value Ccc24.</summary>
[ValueName("Ccc24"), Display(Name = "Ccc24")]
Ccc24 = 24,
/// <summary>Represents the value Ccc25.</summary>
[ValueName("Ccc25"), Display(Name = "Ccc25")]
Ccc25 = 25,
/// <summary>Represents the value Ccc26.</summary>
[ValueName("Ccc26"), Display(Name = "Ccc26")]
Ccc26 = 26,
/// <summary>Represents the value Ccc27.</summary>
[ValueName("Ccc27"), Display(Name = "Ccc27")]
Ccc27 = 27,
/// <summary>Represents the value Ccc28.</summary>
[ValueName("Ccc28"), Display(Name = "Ccc28")]
Ccc28 = 28,
/// <summary>Represents the value Ccc29.</summary>
[ValueName("Ccc29"), Display(Name = "Ccc29")]
Ccc29 = 29,
/// <summary>Represents the value Ccc30.</summary>
[ValueName("Ccc30"), Display(Name = "Ccc30")]
Ccc30 = 30,
/// <summary>Represents the value Ccc31.</summary>
[ValueName("Ccc31"), Display(Name = "Ccc31")]
Ccc31 = 31,
/// <summary>Represents the value Ccc32.</summary>
[ValueName("Ccc32"), Display(Name = "Ccc32")]
Ccc32 = 32,
/// <summary>Represents the value Ccc33.</summary>
[ValueName("Ccc33"), Display(Name = "Ccc33")]
Ccc33 = 33,
/// <summary>Represents the value Ccc34.</summary>
[ValueName("Ccc34"), Display(Name = "Ccc34")]
Ccc34 = 34,
/// <summary>Represents the value Ccc35.</summary>
[ValueName("Ccc35"), Display(Name = "Ccc35")]
Ccc35 = 35,
/// <summary>Represents the value Ccc36.</summary>
[ValueName("Ccc36"), Display(Name = "Ccc36")]
Ccc36 = 36,
/// <summary>Represents the value Ccc37.</summary>
[ValueName("Ccc37"), Display(Name = "Ccc37")]
Ccc37 = 37,
/// <summary>Represents the value Ccc38.</summary>
[ValueName("Ccc38"), Display(Name = "Ccc38")]
Ccc38 = 38,
/// <summary>Represents the value Ccc39.</summary>
[ValueName("Ccc39"), Display(Name = "Ccc39")]
Ccc39 = 39,
/// <summary>Represents the value Ccc40.</summary>
[ValueName("Ccc40"), Display(Name = "Ccc40")]
Ccc40 = 40,
/// <summary>Represents the value Ccc41.</summary>
[ValueName("Ccc41"), Display(Name = "Ccc41")]
Ccc41 = 41,
/// <summary>Represents the value Ccc42.</summary>
[ValueName("Ccc42"), Display(Name = "Ccc42")]
Ccc42 = 42,
/// <summary>Represents the value Ccc43.</summary>
[ValueName("Ccc43"), Display(Name = "Ccc43")]
Ccc43 = 43,
/// <summary>Represents the value Ccc44.</summary>
[ValueName("Ccc44"), Display(Name = "Ccc44")]
Ccc44 = 44,
/// <summary>Represents the value Ccc45.</summary>
[ValueName("Ccc45"), Display(Name = "Ccc45")]
Ccc45 = 45,
/// <summary>Represents the value Ccc46.</summary>
[ValueName("Ccc46"), Display(Name = "Ccc46")]
Ccc46 = 46,
/// <summary>Represents the value Ccc47.</summary>
[ValueName("Ccc47"), Display(Name = "Ccc47")]
Ccc47 = 47,
/// <summary>Represents the value Ccc48.</summary>
[ValueName("Ccc48"), Display(Name = "Ccc48")]
Ccc48 = 48,
/// <summary>Represents the value Ccc49.</summary>
[ValueName("Ccc49"), Display(Name = "Ccc49")]
Ccc49 = 49,
/// <summary>Represents the value Ccc50.</summary>
[ValueName("Ccc50"), Display(Name = "Ccc50")]
Ccc50 = 50,
/// <summary>Represents the value Ccc51.</summary>
[ValueName("Ccc51"), Display(Name = "Ccc51")]
Ccc51 = 51,
/// <summary>Represents the value Ccc52.</summary>
[ValueName("Ccc52"), Display(Name = "Ccc52")]
Ccc52 = 52,
/// <summary>Represents the value Ccc53.</summary>
[ValueName("Ccc53"), Display(Name = "Ccc53")]
Ccc53 = 53,
/// <summary>Represents the value Ccc54.</summary>
[ValueName("Ccc54"), Display(Name = "Ccc54")]
Ccc54 = 54,
/// <summary>Represents the value Ccc55.</summary>
[ValueName("Ccc55"), Display(Name = "Ccc55")]
Ccc55 = 55,
/// <summary>Represents the value Ccc56.</summary>
[ValueName("Ccc56"), Display(Name = "Ccc56")]
Ccc56 = 56,
/// <summary>Represents the value Ccc57.</summary>
[ValueName("Ccc57"), Display(Name = "Ccc57")]
Ccc57 = 57,
/// <summary>Represents the value Ccc58.</summary>
[ValueName("Ccc58"), Display(Name = "Ccc58")]
Ccc58 = 58,
/// <summary>Represents the value Ccc59.</summary>
[ValueName("Ccc59"), Display(Name = "Ccc59")]
Ccc59 = 59,
/// <summary>Represents the value Ccc60.</summary>
[ValueName("Ccc60"), Display(Name = "Ccc60")]
Ccc60 = 60,
/// <summary>Represents the value Ccc61.</summary>
[ValueName("Ccc61"), Display(Name = "Ccc61")]
Ccc61 = 61,
/// <summary>Represents the value Ccc62.</summary>
[ValueName("Ccc62"), Display(Name = "Ccc62")]
Ccc62 = 62,
/// <summary>Represents the value Ccc63.</summary>
[ValueName("Ccc63"), Display(Name = "Ccc63")]
Ccc63 = 63,
/// <summary>Represents the value Ccc64.</summary>
[ValueName("Ccc64"), Display(Name = "Ccc64")]
Ccc64 = 64,
/// <summary>Represents the value Ccc65.</summary>
[ValueName("Ccc65"), Display(Name = "Ccc65")]
Ccc65 = 65,
/// <summary>Represents the value Ccc66.</summary>
[ValueName("Ccc66"), Display(Name = "Ccc66")]
Ccc66 = 66,
/// <summary>Represents the value Ccc67.</summary>
[ValueName("Ccc67"), Display(Name = "Ccc67")]
Ccc67 = 67,
/// <summary>Represents the value Ccc68.</summary>
[ValueName("Ccc68"), Display(Name = "Ccc68")]
Ccc68 = 68,
/// <summary>Represents the value Ccc69.</summary>
[ValueName("Ccc69"), Display(Name = "Ccc69")]
Ccc69 = 69,
/// <summary>Represents the value Ccc70.</summary>
[ValueName("Ccc70"), Display(Name = "Ccc70")]
Ccc70 = 70,
/// <summary>Represents the value Ccc71.</summary>
[ValueName("Ccc71"), Display(Name = "Ccc71")]
Ccc71 = 71,
/// <summary>Represents the value Ccc72.</summary>
[ValueName("Ccc72"), Display(Name = "Ccc72")]
Ccc72 = 72,
/// <summary>Represents the value Ccc73.</summary>
[ValueName("Ccc73"), Display(Name = "Ccc73")]
Ccc73 = 73,
/// <summary>Represents the value Ccc74.</summary>
[ValueName("Ccc74"), Display(Name = "Ccc74")]
Ccc74 = 74,
/// <summary>Represents the value Ccc75.</summary>
[ValueName("Ccc75"), Display(Name = "Ccc75")]
Ccc75 = 75,
/// <summary>Represents the value Ccc76.</summary>
[ValueName("Ccc76"), Display(Name = "Ccc76")]
Ccc76 = 76,
/// <summary>Represents the value Ccc77.</summary>
[ValueName("Ccc77"), Display(Name = "Ccc77")]
Ccc77 = 77,
/// <summary>Represents the value Ccc78.</summary>
[ValueName("Ccc78"), Display(Name = "Ccc78")]
Ccc78 = 78,
/// <summary>Represents the value Ccc79.</summary>
[ValueName("Ccc79"), Display(Name = "Ccc79")]
Ccc79 = 79,
/// <summary>Represents the value Ccc80.</summary>
[ValueName("Ccc80"), Display(Name = "Ccc80")]
Ccc80 = 80,
/// <summary>Represents the value Ccc81.</summary>
[ValueName("Ccc81"), Display(Name = "Ccc81")]
Ccc81 = 81,
/// <summary>Represents the value Ccc82.</summary>
[ValueName("Ccc82"), Display(Name = "Ccc82")]
Ccc82 = 82,
/// <summary>Represents the value Ccc83.</summary>
[ValueName("Ccc83"), Display(Name = "Ccc83")]
Ccc83 = 83,
/// <summary>Represents the value Ccc84.</summary>
[ValueName("Ccc84"), Display(Name = "Ccc84")]
Ccc84 = 84,
/// <summary>Represents the value Ccc85.</summary>
[ValueName("Ccc85"), Display(Name = "Ccc85")]
Ccc85 = 85,
/// <summary>Represents the value Ccc86.</summary>
[ValueName("Ccc86"), Display(Name = "Ccc86")]
Ccc86 = 86,
/// <summary>Represents the value Ccc87.</summary>
[ValueName("Ccc87"), Display(Name = "Ccc87")]
Ccc87 = 87,
/// <summary>Represents the value Ccc88.</summary>
[ValueName("Ccc88"), Display(Name = "Ccc88")]
Ccc88 = 88,
/// <summary>Represents the value Ccc89.</summary>
[ValueName("Ccc89"), Display(Name = "Ccc89")]
Ccc89 = 89,
/// <summary>Represents the value Ccc90.</summary>
[ValueName("Ccc90"), Display(Name = "Ccc90")]
Ccc90 = 90,
/// <summary>Represents the value Ccc91.</summary>
[ValueName("Ccc91"), Display(Name = "Ccc91")]
Ccc91 = 91,
/// <summary>Represents the value Ccc92.</summary>
[ValueName("Ccc92"), Display(Name = "Ccc92")]
Ccc92 = 92,
/// <summary>Represents the value Ccc93.</summary>
[ValueName("Ccc93"), Display(Name = "Ccc93")]
Ccc93 = 93,
/// <summary>Represents the value Ccc94.</summary>
[ValueName("Ccc94"), Display(Name = "Ccc94")]
Ccc94 = 94,
/// <summary>Represents the value Ccc95.</summary>
[ValueName("Ccc95"), Display(Name = "Ccc95")]
Ccc95 = 95,
/// <summary>Represents the value Ccc96.</summary>
[ValueName("Ccc96"), Display(Name = "Ccc96")]
Ccc96 = 96,
/// <summary>Represents the value Ccc97.</summary>
[ValueName("Ccc97"), Display(Name = "Ccc97")]
Ccc97 = 97,
/// <summary>Represents the value Ccc98.</summary>
[ValueName("Ccc98"), Display(Name = "Ccc98")]
Ccc98 = 98,
/// <summary>Represents the value Ccc99.</summary>
[ValueName("Ccc99"), Display(Name = "Ccc99")]
Ccc99 = 99,
/// <summary>Represents the value Ccc100.</summary>
[ValueName("Ccc100"), Display(Name = "Ccc100")]
Ccc100 = 100,
/// <summary>Represents the value Ccc101.</summary>
[ValueName("Ccc101"), Display(Name = "Ccc101")]
Ccc101 = 101,
/// <summary>Represents the value Ccc102.</summary>
[ValueName("Ccc102"), Display(Name = "Ccc102")]
Ccc102 = 102,
/// <summary>Represents the value Ccc103.</summary>
[ValueName("Ccc103"), Display(Name = "Ccc103")]
Ccc103 = 103,
/// <summary>Represents the value Ccc104.</summary>
[ValueName("Ccc104"), Display(Name = "Ccc104")]
Ccc104 = 104,
/// <summary>Represents the value Ccc105.</summary>
[ValueName("Ccc105"), Display(Name = "Ccc105")]
Ccc105 = 105,
/// <summary>Represents the value Ccc106.</summary>
[ValueName("Ccc106"), Display(Name = "Ccc106")]
Ccc106 = 106,
/// <summary>Represents the value Ccc107.</summary>
[ValueName("Ccc107"), Display(Name = "Ccc107")]
Ccc107 = 107,
/// <summary>Represents the value Ccc108.</summary>
[ValueName("Ccc108"), Display(Name = "Ccc108")]
Ccc108 = 108,
/// <summary>Represents the value Ccc109.</summary>
[ValueName("Ccc109"), Display(Name = "Ccc109")]
Ccc109 = 109,
/// <summary>Represents the value Ccc110.</summary>
[ValueName("Ccc110"), Display(Name = "Ccc110")]
Ccc110 = 110,
/// <summary>Represents the value Ccc111.</summary>
[ValueName("Ccc111"), Display(Name = "Ccc111")]
Ccc111 = 111,
/// <summary>Represents the value Ccc112.</summary>
[ValueName("Ccc112"), Display(Name = "Ccc112")]
Ccc112 = 112,
/// <summary>Represents the value Ccc113.</summary>
[ValueName("Ccc113"), Display(Name = "Ccc113")]
Ccc113 = 113,
/// <summary>Represents the value Ccc114.</summary>
[ValueName("Ccc114"), Display(Name = "Ccc114")]
Ccc114 = 114,
/// <summary>Represents the value Ccc115.</summary>
[ValueName("Ccc115"), Display(Name = "Ccc115")]
Ccc115 = 115,
/// <summary>Represents the value Ccc116.</summary>
[ValueName("Ccc116"), Display(Name = "Ccc116")]
Ccc116 = 116,
/// <summary>Represents the value Ccc117.</summary>
[ValueName("Ccc117"), Display(Name = "Ccc117")]
Ccc117 = 117,
/// <summary>Represents the value Ccc118.</summary>
[ValueName("Ccc118"), Display(Name = "Ccc118")]
Ccc118 = 118,
/// <summary>Represents the value Ccc119.</summary>
[ValueName("Ccc119"), Display(Name = "Ccc119")]
Ccc119 = 119,
/// <summary>Represents the value Ccc120.</summary>
[ValueName("Ccc120"), Display(Name = "Ccc120")]
Ccc120 = 120,
/// <summary>Represents the value Ccc121.</summary>
[ValueName("Ccc121"), Display(Name = "Ccc121")]
Ccc121 = 121,
/// <summary>Represents the value Ccc122.</summary>
[ValueName("Ccc122"), Display(Name = "Ccc122")]
Ccc122 = 122,
/// <summary>Represents the value Ccc123.</summary>
[ValueName("Ccc123"), Display(Name = "Ccc123")]
Ccc123 = 123,
/// <summary>Represents the value Ccc124.</summary>
[ValueName("Ccc124"), Display(Name = "Ccc124")]
Ccc124 = 124,
/// <summary>Represents the value Ccc125.</summary>
[ValueName("Ccc125"), Display(Name = "Ccc125")]
Ccc125 = 125,
/// <summary>Represents the value Ccc126.</summary>
[ValueName("Ccc126"), Display(Name = "Ccc126")]
Ccc126 = 126,
/// <summary>Represents the value Ccc127.</summary>
[ValueName("Ccc127"), Display(Name = "Ccc127")]
Ccc127 = 127,
/// <summary>Represents the value Ccc128.</summary>
[ValueName("Ccc128"), Display(Name = "Ccc128")]
Ccc128 = 128,
/// <summary>Represents the value Ccc129.</summary>
[ValueName("Ccc129"), Display(Name = "Ccc129")]
Ccc129 = 129,
/// <summary>Represents the value Ccc130.</summary>
[ValueName("Ccc130"), Display(Name = "Ccc130")]
Ccc130 = 130,
/// <summary>Represents the value Ccc131.</summary>
[ValueName("Ccc131"), Display(Name = "Ccc131")]
Ccc131 = 131,
/// <summary>Represents the value Ccc132.</summary>
[ValueName("Ccc132"), Display(Name = "Ccc132")]
Ccc132 = 132,
/// <summary>Represents the value Ccc133.</summary>
[ValueName("Ccc133"), Display(Name = "Ccc133")]
Ccc133 = 133,
/// <summary>Represents the value Ccc134.</summary>
[ValueName("Ccc134"), Display(Name = "Ccc134")]
Ccc134 = 134,
/// <summary>Represents the value Ccc135.</summary>
[ValueName("Ccc135"), Display(Name = "Ccc135")]
Ccc135 = 135,
/// <summary>Represents the value Ccc136.</summary>
[ValueName("Ccc136"), Display(Name = "Ccc136")]
Ccc136 = 136,
/// <summary>Represents the value Ccc137.</summary>
[ValueName("Ccc137"), Display(Name = "Ccc137")]
Ccc137 = 137,
/// <summary>Represents the value Ccc138.</summary>
[ValueName("Ccc138"), Display(Name = "Ccc138")]
Ccc138 = 138,
/// <summary>Represents the value Ccc139.</summary>
[ValueName("Ccc139"), Display(Name = "Ccc139")]
Ccc139 = 139,
/// <summary>Represents the value Ccc140.</summary>
[ValueName("Ccc140"), Display(Name = "Ccc140")]
Ccc140 = 140,
/// <summary>Represents the value Ccc141.</summary>
[ValueName("Ccc141"), Display(Name = "Ccc141")]
Ccc141 = 141,
/// <summary>Represents the value Ccc142.</summary>
[ValueName("Ccc142"), Display(Name = "Ccc142")]
Ccc142 = 142,
/// <summary>Represents the value Ccc143.</summary>
[ValueName("Ccc143"), Display(Name = "Ccc143")]
Ccc143 = 143,
/// <summary>Represents the value Ccc144.</summary>
[ValueName("Ccc144"), Display(Name = "Ccc144")]
Ccc144 = 144,
/// <summary>Represents the value Ccc145.</summary>
[ValueName("Ccc145"), Display(Name = "Ccc145")]
Ccc145 = 145,
/// <summary>Represents the value Ccc146.</summary>
[ValueName("Ccc146"), Display(Name = "Ccc146")]
Ccc146 = 146,
/// <summary>Represents the value Ccc147.</summary>
[ValueName("Ccc147"), Display(Name = "Ccc147")]
Ccc147 = 147,
/// <summary>Represents the value Ccc148.</summary>
[ValueName("Ccc148"), Display(Name = "Ccc148")]
Ccc148 = 148,
/// <summary>Represents the value Ccc149.</summary>
[ValueName("Ccc149"), Display(Name = "Ccc149")]
Ccc149 = 149,
/// <summary>Represents the value Ccc150.</summary>
[ValueName("Ccc150"), Display(Name = "Ccc150")]
Ccc150 = 150,
/// <summary>Represents the value Ccc151.</summary>
[ValueName("Ccc151"), Display(Name = "Ccc151")]
Ccc151 = 151,
/// <summary>Represents the value Ccc152.</summary>
[ValueName("Ccc152"), Display(Name = "Ccc152")]
Ccc152 = 152,
/// <summary>Represents the value Ccc153.</summary>
[ValueName("Ccc153"), Display(Name = "Ccc153")]
Ccc153 = 153,
/// <summary>Represents the value Ccc154.</summary>
[ValueName("Ccc154"), Display(Name = "Ccc154")]
Ccc154 = 154,
/// <summary>Represents the value Ccc155.</summary>
[ValueName("Ccc155"), Display(Name = "Ccc155")]
Ccc155 = 155,
/// <summary>Represents the value Ccc156.</summary>
[ValueName("Ccc156"), Display(Name = "Ccc156")]
Ccc156 = 156,
/// <summary>Represents the value Ccc157.</summary>
[ValueName("Ccc157"), Display(Name = "Ccc157")]
Ccc157 = 157,
/// <summary>Represents the value Ccc158.</summary>
[ValueName("Ccc158"), Display(Name = "Ccc158")]
Ccc158 = 158,
/// <summary>Represents the value Ccc159.</summary>
[ValueName("Ccc159"), Display(Name = "Ccc159")]
Ccc159 = 159,
/// <summary>Represents the value Ccc160.</summary>
[ValueName("Ccc160"), Display(Name = "Ccc160")]
Ccc160 = 160,
/// <summary>Represents the value Ccc161.</summary>
[ValueName("Ccc161"), Display(Name = "Ccc161")]
Ccc161 = 161,
/// <summary>Represents the value Ccc162.</summary>
[ValueName("Ccc162"), Display(Name = "Ccc162")]
Ccc162 = 162,
/// <summary>Represents the value Ccc163.</summary>
[ValueName("Ccc163"), Display(Name = "Ccc163")]
Ccc163 = 163,
/// <summary>Represents the value Ccc164.</summary>
[ValueName("Ccc164"), Display(Name = "Ccc164")]
Ccc164 = 164,
/// <summary>Represents the value Ccc165.</summary>
[ValueName("Ccc165"), Display(Name = "Ccc165")]
Ccc165 = 165,
/// <summary>Represents the value Ccc166.</summary>
[ValueName("Ccc166"), Display(Name = "Ccc166")]
Ccc166 = 166,
/// <summary>Represents the value Ccc167.</summary>
[ValueName("Ccc167"), Display(Name = "Ccc167")]
Ccc167 = 167,
/// <summary>Represents the value Ccc168.</summary>
[ValueName("Ccc168"), Display(Name = "Ccc168")]
Ccc168 = 168,
/// <summary>Represents the value Ccc169.</summary>
[ValueName("Ccc169"), Display(Name = "Ccc169")]
Ccc169 = 169,
/// <summary>Represents the value Ccc170.</summary>
[ValueName("Ccc170"), Display(Name = "Ccc170")]
Ccc170 = 170,
/// <summary>Represents the value Ccc171.</summary>
[ValueName("Ccc171"), Display(Name = "Ccc171")]
Ccc171 = 171,
/// <summary>Represents the value Ccc172.</summary>
[ValueName("Ccc172"), Display(Name = "Ccc172")]
Ccc172 = 172,
/// <summary>Represents the value Ccc173.</summary>
[ValueName("Ccc173"), Display(Name = "Ccc173")]
Ccc173 = 173,
/// <summary>Represents the value Ccc174.</summary>
[ValueName("Ccc174"), Display(Name = "Ccc174")]
Ccc174 = 174,
/// <summary>Represents the value Ccc175.</summary>
[ValueName("Ccc175"), Display(Name = "Ccc175")]
Ccc175 = 175,
/// <summary>Represents the value Ccc176.</summary>
[ValueName("Ccc176"), Display(Name = "Ccc176")]
Ccc176 = 176,
/// <summary>Represents the value Ccc177.</summary>
[ValueName("Ccc177"), Display(Name = "Ccc177")]
Ccc177 = 177,
/// <summary>Represents the value Ccc178.</summary>
[ValueName("Ccc178"), Display(Name = "Ccc178")]
Ccc178 = 178,
/// <summary>Represents the value Ccc179.</summary>
[ValueName("Ccc179"), Display(Name = "Ccc179")]
Ccc179 = 179,
/// <summary>Represents the value Ccc180.</summary>
[ValueName("Ccc180"), Display(Name = "Ccc180")]
Ccc180 = 180,
/// <summary>Represents the value Ccc181.</summary>
[ValueName("Ccc181"), Display(Name = "Ccc181")]
Ccc181 = 181,
/// <summary>Represents the value Ccc182.</summary>
[ValueName("Ccc182"), Display(Name = "Ccc182")]
Ccc182 = 182,
/// <summary>Represents the value Ccc183.</summary>
[ValueName("Ccc183"), Display(Name = "Ccc183")]
Ccc183 = 183,
/// <summary>Represents the value Ccc184.</summary>
[ValueName("Ccc184"), Display(Name = "Ccc184")]
Ccc184 = 184,
/// <summary>Represents the value Ccc185.</summary>
[ValueName("Ccc185"), Display(Name = "Ccc185")]
Ccc185 = 185,
/// <summary>Represents the value Ccc186.</summary>
[ValueName("Ccc186"), Display(Name = "Ccc186")]
Ccc186 = 186,
/// <summary>Represents the value Ccc187.</summary>
[ValueName("Ccc187"), Display(Name = "Ccc187")]
Ccc187 = 187,
/// <summary>Represents the value Ccc188.</summary>
[ValueName("Ccc188"), Display(Name = "Ccc188")]
Ccc188 = 188,
/// <summary>Represents the value Ccc189.</summary>
[ValueName("Ccc189"), Display(Name = "Ccc189")]
Ccc189 = 189,
/// <summary>Represents the value Ccc190.</summary>
[ValueName("Ccc190"), Display(Name = "Ccc190")]
Ccc190 = 190,
/// <summary>Represents the value Ccc191.</summary>
[ValueName("Ccc191"), Display(Name = "Ccc191")]
Ccc191 = 191,
/// <summary>Represents the value Ccc192.</summary>
[ValueName("Ccc192"), Display(Name = "Ccc192")]
Ccc192 = 192,
/// <summary>Represents the value Ccc193.</summary>
[ValueName("Ccc193"), Display(Name = "Ccc193")]
Ccc193 = 193,
/// <summary>Represents the value Ccc194.</summary>
[ValueName("Ccc194"), Display(Name = "Ccc194")]
Ccc194 = 194,
/// <summary>Represents the value Ccc195.</summary>
[ValueName("Ccc195"), Display(Name = "Ccc195")]
Ccc195 = 195,
/// <summary>Represents the value Ccc196.</summary>
[ValueName("Ccc196"), Display(Name = "Ccc196")]
Ccc196 = 196,
/// <summary>Represents the value Ccc197.</summary>
[ValueName("Ccc197"), Display(Name = "Ccc197")]
Ccc197 = 197,
/// <summary>Represents the value Ccc198.</summary>
[ValueName("Ccc198"), Display(Name = "Ccc198")]
Ccc198 = 198,
/// <summary>Represents the value Ccc199.</summary>
[ValueName("Ccc199"), Display(Name = "Ccc199", Description = "End of fixed position classes")]
Ccc199 = 199,
/// <summary>Represents the value Attached_Below_Left.</summary>
[ValueName("Attached_Below_Left"), Display(Name = "Attached_Below_Left", Description = "Marks attached at the bottom left")]
AttachedBelowLeft = 200,
/// <summary>Represents the value Attached_Below.</summary>
[ValueName("Attached_Below"), Display(Name = "Attached_Below", Description = "Marks attached directly below")]
AttachedBelow = 202,
/// <summary>Represents the value Attached_Below_Right.</summary>
[ValueName("Attached_Below_Right"), Display(Name = "Attached_Below_Right", Description = "Marks attached at the bottom right")]
AttachedBelowRight = 204,
/// <summary>Represents the value Attached_Left.</summary>
[ValueName("Attached_Left"), Display(Name = "Attached_Left", Description = "Marks attached to the left")]
AttachedLeft = 208,
/// <summary>Represents the value Attached_Right.</summary>
[ValueName("Attached_Right"), Display(Name = "Attached_Right", Description = "Marks attached to the right")]
AttachedRight = 210,
/// <summary>Represents the value Attached_Above_Left.</summary>
[ValueName("Attached_Above_Left"), Display(Name = "Attached_Above_Left", Description = "Marks attached at the top left")]
AttachedAboveLeft = 212,
/// <summary>Represents the value Attached_Above.</summary>
[ValueName("Attached_Above"), Display(Name = "Attached_Above", Description = "Marks attached directly above")]
AttachedAbove = 214,
/// <summary>Represents the value Attached_Above_Right.</summary>
[ValueName("Attached_Above_Right"), Display(Name = "Attached_Above_Right", Description = "Marks attached at the top right")]
AttachedAboveRight = 216,
/// <summary>Represents the value Below_Left.</summary>
[ValueName("Below_Left"), Display(Name = "Below_Left", Description = "Distinct marks at the bottom left")]
BelowLeft = 218,
/// <summary>Represents the value Below.</summary>
[ValueName("Below"), Display(Name = "Below", Description = "Distinct marks directly below")]
Below = 220,
/// <summary>Represents the value Below_Right.</summary>
[ValueName("Below_Right"), Display(Name = "Below_Right", Description = "Distinct marks at the bottom right")]
BelowRight = 222,
/// <summary>Represents the value Left.</summary>
[ValueName("Left"), Display(Name = "Left", Description = "Distinct marks to the left")]
Left = 224,
/// <summary>Represents the value Right.</summary>
[ValueName("Right"), Display(Name = "Right", Description = "Distinct marks to the right")]
Right = 226,
/// <summary>Represents the value Above_Left.</summary>
[ValueName("Above_Left"), Display(Name = "Above_Left", Description = "Distinct marks at the top left")]
AboveLeft = 228,
/// <summary>Represents the value Above.</summary>
[ValueName("Above"), Display(Name = "Above", Description = "Distinct marks directly above")]
Above = 230,
/// <summary>Represents the value Above_Right.</summary>
[ValueName("Above_Right"), Display(Name = "Above_Right", Description = "Distinct marks at the top right")]
AboveRight = 232,
/// <summary>Represents the value Double_Below.</summary>
[ValueName("Double_Below"), Display(Name = "Double_Below", Description = "Distinct marks subtending two bases")]
DoubleBelow = 233,
/// <summary>Represents the value Double_Above.</summary>
[ValueName("Double_Above"), Display(Name = "Double_Above", Description = "Distinct marks extending above two bases")]
DoubleAbove = 234,
/// <summary>Represents the value Iota_Subscript.</summary>
[ValueName("Iota_Subscript"), Display(Name = "Iota_Subscript", Description = "Greek iota subscript only")]
IotaSubscript = 240,
}
+19 -5
View File
@@ -1,23 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace System.Unicode
{
/// <summary>Provides information on a specific CJK radical.</summary>
[DebuggerDisplay("{RadicalIndex} - {TraditionalRadicalCodePoint.ToString(),nq} / {SimplifiedRadicalCodePoint.ToString(),nq}")]
public struct CjkRadicalInfo
{
private readonly byte radicalIndex;
private readonly CjkRadicalData radicalData;
/// <summary>The index of the radical in the Kangxi dictionary.</summary>
/// <remarks>There are 214 radicals, numbered from 1 to 214.</remarks>
public byte RadicalIndex { get { return radicalIndex; } }
/// <summary>Gets a code point representing the CJK radical in its traditional form.</summary>
public char TraditionalRadicalCodePoint { get { return radicalData.TraditionalRadicalCodePoint; } }
/// <summary>Gets the code point of a traditional character composed only of the CJK radical.</summary>
/// <remarks>
/// Usually, the glyph of this code point will be the same as the one used for <see cref="TraditionalRadicalCodePoint"/>.
/// However, the code point returned will have a meaning associated, contrary to the one returned by <see cref="TraditionalRadicalCodePoint"/>, which only represents the radical.
/// </remarks>
public char TraditionalCharacterCodePoint { get { return radicalData.TraditionalCharacterCodePoint; } }
/// <summary>Gets a code point representing the CJK radical in its simplified form, which may be the same as the traditional form.</summary>
/// <remarks>Most of the time, the value returned will be the same as <see cref="TraditionalRadicalCodePoint"/>.</remarks>
public char SimplifiedRadicalCodePoint { get { return radicalData.SimplifiedRadicalCodePoint; } }
/// <summary>Gets the code point of a simplified character composed only of the CJK radical.</summary>
/// <remarks>
/// Usually, the glyph of this code point will be the same as the one used for <see cref="SimplifiedRadicalCodePoint"/>.
/// However, the code point returned will have a meaning associated, contrary to the one returned by <see cref="SimplifiedRadicalCodePoint"/>, which only represents the radical.
/// </remarks>
public char SimplifiedCharacterCodePoint { get { return radicalData.SimplifiedCharacterCodePoint; } }
/// <summary>Gets a value indicating whether a simplified form exists for the given radical.</summary>
public bool HasSimplifiedForm { get { return radicalData.HasSimplifiedForm; } }
internal CjkRadicalInfo(byte radicalIndex, CjkRadicalData radicalData)
+15 -24
View File
@@ -1,36 +1,27 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Allows enumeration of the code points contained in an encapsulated string.</summary>
/// <remarks>
/// This enumerable will only allow enumeration of valid UTF-16 strings.
/// For incomplete or invalid UTF-16 strings, please use <see cref="PermissiveCodePointEnumerable"/> instead.
/// </remarks>
public struct CodePointEnumerable : IEnumerable<int>
{
private readonly string text;
/// <summary>Initializes a new instance of the struct <see cref="CodePointEnumerable"/>.</summary>
/// <param name="text">The string whose code points must be enumerated.</param>
public CodePointEnumerable(string text) => Text = text ?? throw new ArgumentNullException(nameof(text));
public CodePointEnumerable(string text)
{
this.text = text;
}
/// <summary>Gets the text whose code points are being enumerated.</summary>
public string Text { get; }
public string Text { get { return text; } }
/// <summary>Gets an enumerator which can be used to enumerate the code points in the text.</summary>
public CodePointEnumerator GetEnumerator() => new CodePointEnumerator(Text);
public CodePointEnumerator GetEnumerator()
{
return new CodePointEnumerator(text);
}
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
+11 -7
View File
@@ -1,18 +1,18 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Supports a standard iteration of code points in a <see cref="string"/>.</summary>
public struct CodePointEnumerator : IEnumerator<int>
{
private readonly string text;
private int current;
private int index;
/// <summary>Initializes a new instance of the <see cref="PermissiveCodePointEnumerator"/> struct.</summary>
/// <param name="text">The text whose code point should be enumerated.</param>
/// <exception cref="ArgumentNullException"><paramref cref="text"/> is <see langword="null"/>.</exception>
public CodePointEnumerator(string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
@@ -22,12 +22,16 @@ namespace System.Unicode
this.index = -1;
}
public int Current { get { return current; } }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public int Current => current;
object IEnumerator.Current { get { return current; } }
object IEnumerator.Current => current;
void IDisposable.Dispose() { }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns><see langword="true"/> if the enumerator was successfully advanced to the next element; <see langword="false"/> if the enumerator has passed the end of the collection.</returns>
public bool MoveNext()
{
if (index < text.Length && (index += current > 0xFFFF ? 2 : 1) < text.Length)
@@ -1,46 +1,60 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace System.Unicode
{
/// <summary>Provides information on the kind of compatibility decomposition provided.</summary>
/// <remarks>The default value of <see cref="CompatibilityFormattingTag.Canonical"/> indicates canonical decomposition of the code point.</remarks>
public enum CompatibilityFormattingTag : byte
{
/// <summary>Canonical form.</summary>
Canonical = 0,
[ValueName("font"), Display(Name = "font", Description = "Font variant (for example, a blackletter form)")]
/// <summary>Font variant (for example, a blackletter form).</summary>
[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")]
/// <summary>No-break version of a space or hyphen.</summary>
[ValueName("noBreak"), Display(Name = "noBreak", Description = "No-break version of a space or hyphen.")]
NoBreak,
[ValueName("initial"), Display(Name = "initial", Description = "Initial presentation form (Arabic)")]
/// <summary>Initial presentation form (Arabic).</summary>
[ValueName("initial"), Display(Name = "initial", Description = "Initial presentation form (Arabic).")]
Initial,
[ValueName("medial"), Display(Name = "medial", Description = "Medial presentation form (Arabic)")]
/// <summary>Medial presentation form (Arabic).</summary>
[ValueName("medial"), Display(Name = "medial", Description = "Medial presentation form (Arabic).")]
Medial,
[ValueName("final"), Display(Name = "final", Description = "Final presentation form (Arabic)")]
/// <summary>Final presentation form (Arabic).</summary>
[ValueName("final"), Display(Name = "final", Description = "Final presentation form (Arabic).")]
Final,
[ValueName("isolated"), Display(Name = "isolated", Description = "Isolated presentation form (Arabic)")]
/// <summary>Isolated presentation form (Arabic).</summary>
[ValueName("isolated"), Display(Name = "isolated", Description = "Isolated presentation form (Arabic).")]
Isolated,
[ValueName("circle"), Display(Name = "circle", Description = "Encircled form")]
/// <summary>Encircled form.</summary>
[ValueName("circle"), Display(Name = "circle", Description = "Encircled form.")]
Circle,
[ValueName("super"), Display(Name = "super", Description = "Superscript form")]
/// <summary>Superscript form.</summary>
[ValueName("super"), Display(Name = "super", Description = "Superscript form.")]
Super,
[ValueName("sub"), Display(Name = "sub", Description = "Subscript form")]
/// <summary>Subscript form.</summary>
[ValueName("sub"), Display(Name = "sub", Description = "Subscript form.")]
Sub,
[ValueName("vertical"), Display(Name = "vertical", Description = "Vertical layout presentation form")]
/// <summary>Vertical layout presentation form.</summary>
[ValueName("vertical"), Display(Name = "vertical", Description = "Vertical layout presentation form.")]
Vertical,
[ValueName("wide"), Display(Name = "wide", Description = "Wide (or zenkaku) compatibility character")]
/// <summary>Wide (or zenkaku) compatibility character.</summary>
[ValueName("wide"), Display(Name = "wide", Description = "Wide (or zenkaku) compatibility character.")]
Wide,
[ValueName("narrow"), Display(Name = "narrow", Description = "Narrow (or hankaku) compatibility character")]
/// <summary>Narrow (or hankaku) compatibility character.</summary>
[ValueName("narrow"), Display(Name = "narrow", Description = "Narrow (or hankaku) compatibility character.")]
Narrow,
[ValueName("small"), Display(Name = "small", Description = "Small variant form (CNS compatibility)")]
/// <summary>Small variant form (CNS compatibility).</summary>
[ValueName("small"), Display(Name = "small", Description = "Small variant form (CNS compatibility).")]
Small,
[ValueName("square"), Display(Name = "square", Description = "CJK squared font variant")]
/// <summary>CJK squared font variant.</summary>
[ValueName("square"), Display(Name = "square", Description = "CJK squared font variant.")]
Square,
[ValueName("fraction"), Display(Name = "fraction", Description = "Vulgar fraction form")]
/// <summary>Vulgar fraction form.</summary>
[ValueName("fraction"), Display(Name = "fraction", Description = "Vulgar fraction form.")]
Fraction,
[ValueName("compat"), Display(Name = "compat", Description = "Otherwise unspecified compatibility character")]
/// <summary>Otherwise unspecified compatibility character.</summary>
[ValueName("compat"), Display(Name = "compat", Description = "Otherwise unspecified compatibility character.")]
Compat,
}
}
+73 -14
View File
@@ -1,79 +1,138 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace System.Unicode
{
/// <summary>A bitmask of the various available contributory properties.</summary>
/// <remarks>As per the standard, contributory properties are neither normative nor informative, but are used to derive <see cref="ContributoryProperties"/>.</remarks>
[Flags]
public enum ContributoryProperties : int
{
None = 0x00000000,
/// <summary>Represents the ASCII_Hex_Digit property.</summary>
/// <remarks>ASCII characters commonly used for the representation of hexadecimal numbers.</remarks>
[ValueName("ASCII_Hex_Digit"), Display(Name = "ASCII_Hex_Digit", Description = "ASCII characters commonly used for the representation of hexadecimal numbers.")]
AsciiHexDigit = 0x00000001,
/// <summary>Represents the Bidi_Control property.</summary>
/// <remarks>Format control characters which have specific functions in the Unicode Bidirectional Algorithm [UAX9].</remarks>
[ValueName("Bidi_Control"), Display(Name = "Bidi_Control", Description = "Format control characters which have specific functions in the Unicode Bidirectional Algorithm [UAX9].")]
BidiControl = 0x00000002,
/// <summary>Represents the Dash property.</summary>
/// <remarks>Punctuation characters explicitly called out as dashes in the Unicode Standard, plus their compatibility equivalents. Most of these have the General_Category value Pd, but some have the General_Category value Sm because of their use in mathematics.</remarks>
[ValueName("Dash"), Display(Name = "Dash", Description = "Punctuation characters explicitly called out as dashes in the Unicode Standard, plus their compatibility equivalents. Most of these have the General_Category value Pd, but some have the General_Category value Sm because of their use in mathematics.")]
Dash = 0x00000004,
/// <summary>Represents the Deprecated property.</summary>
/// <remarks>For a machine-readable list of deprecated characters. No characters will ever be removed from the standard, but the usage of deprecated characters is strongly discouraged.</remarks>
[ValueName("Deprecated"), Display(Name = "Deprecated", Description = "For a machine-readable list of deprecated characters. No characters will ever be removed from the standard, but the usage of deprecated characters is strongly discouraged.")]
Deprecated = 0x00000008,
/// <summary>Represents the Diacritic property.</summary>
/// <remarks>Characters that linguistically modify the meaning of another character to which they apply. Some diacritics are not combining characters, and some combining characters are not diacritics.</remarks>
[ValueName("Diacritic"), Display(Name = "Diacritic", Description = "Characters that linguistically modify the meaning of another character to which they apply. Some diacritics are not combining characters, and some combining characters are not diacritics.")]
Diacritic = 0x00000010,
/// <summary>Represents the Extender property.</summary>
/// <remarks>Characters whose principal function is to extend the value or shape of a preceding alphabetic character. Typical of these are length and iteration marks.</remarks>
[ValueName("Extender"), Display(Name = "Extender", Description = "Characters whose principal function is to extend the value or shape of a preceding alphabetic character. Typical of these are length and iteration marks.")]
Extender = 0x00000020,
/// <summary>Represents the Hex_Digit property.</summary>
/// <remarks>Characters commonly used for the representation of hexadecimal numbers, plus their compatibility equivalents.</remarks>
[ValueName("Hex_Digit"), Display(Name = "Hex_Digit", Description = "Characters commonly used for the representation of hexadecimal numbers, plus their compatibility equivalents.")]
HexDigit = 0x00000040,
[ValueName("Hyphen"), Display(Name = "Hyphen", Description = "Dashes which are used to mark connections between pieces of words, plus the Katakana middle dot. The Katakana middle dotfunctions like a hyphen, but is shaped like a dot rather than a dash.")]
/// <summary>Represents the Hyphen property.</summary>
/// <remarks>Dashes which are used to mark connections between pieces of words, plus the Katakana middle dot. The Katakana middle dotfunctions like a hyphen, but is shaped like a dot rather than a dash.</remarks>
[ValueName("Hyphen"), Display(Name = "Hyphen", Description = "Dashes which are used to mark connections between pieces of words, plus the Katakana middle dot. The Katakana middle dotfunctions like a hyphen, but is shaped like a dot rather than a dash.")]
Hyphen = 0x00000080,
/// <summary>Represents the Ideographic property.</summary>
/// <remarks>Characters considered to be CJKV (Chinese, Japanese, Korean, and Vietnamese) ideographs. This property roughly defines the class of "Chinese characters" and does not include characters of other logographic scripts such as Cuneiform or Egyptian Hieroglyphs.</remarks>
[ValueName("Ideographic"), Display(Name = "Ideographic", Description = "Characters considered to be CJKV (Chinese, Japanese, Korean, and Vietnamese) ideographs. This property roughly defines the class of \"Chinese characters\" and does not include characters of other logographic scripts such as Cuneiform or Egyptian Hieroglyphs.")]
Ideographic = 0x00000100,
/// <summary>Represents the IDS_Binary_Operator property.</summary>
/// <remarks>Used in Ideographic Description Sequences.</remarks>
[ValueName("IDS_Binary_Operator"), Display(Name = "IDS_Binary_Operator", Description = "Used in Ideographic Description Sequences.")]
IdsBinaryOperator = 0x00000200,
/// <summary>Represents the IDS_Trinary_Operator property.</summary>
/// <remarks>Used in Ideographic Description Sequences.</remarks>
[ValueName("IDS_Trinary_Operator"), Display(Name = "IDS_Trinary_Operator", Description = "Used in Ideographic Description Sequences.")]
IdsTrinaryOperator = 0x00000400,
/// <summary>Represents the Join_Control property.</summary>
/// <remarks>Format control characters which have specific functions for control of cursive joining and ligation.</remarks>
[ValueName("Join_Control"), Display(Name = "Join_Control", Description = "Format control characters which have specific functions for control of cursive joining and ligation.")]
JoinControl = 0x00000800,
/// <summary>Represents the Logical_Order_Exception property.</summary>
/// <remarks>A small number of spacing vowel letters occurring in certain Southeast Asian scripts such as Thai and Lao, which use a visual order display model. These letters are stored in text ahead of syllable-initial consonants, and require special handling for processes such as searching and sorting.</remarks>
[ValueName("Logical_Order_Exception"), Display(Name = "Logical_Order_Exception", Description = "A small number of spacing vowel letters occurring in certain Southeast Asian scripts such as Thai and Lao, which use a visual order display model. These letters are stored in text ahead of syllable-initial consonants, and require special handling for processes such as searching and sorting.")]
LogicalOrderException = 0x00001000,
/// <summary>Represents the Noncharacter_Code_Point property.</summary>
/// <remarks>Code points permanently reserved for internal use.</remarks>
[ValueName("Noncharacter_Code_Point"), Display(Name = "Noncharacter_Code_Point", Description = "Code points permanently reserved for internal use.")]
NonCharacterCodePoint = 0x00002000,
/// <summary>Represents the Other_Alphabetic property.</summary>
/// <remarks>Used in deriving the Alphabetic property.</remarks>
[ValueName("Other_Alphabetic"), Display(Name = "Other_Alphabetic", Description = "Used in deriving the Alphabetic property.")]
OtherAlphabetic = 0x00004000,
/// <summary>Represents the Other_Default_Ignorable_Code_Point property.</summary>
/// <remarks>Used in deriving the Default_Ignorable_Code_Point property.</remarks>
[ValueName("Other_Default_Ignorable_Code_Point"), Display(Name = "Other_Default_Ignorable_Code_Point", Description = "Used in deriving the Default_Ignorable_Code_Point property.")]
OtherDefaultIgnorableCodePoint = 0x00008000,
[ValueName("Other_Grapheme_Extend"), Display(Name = "Other_Grapheme_Extend", Description = "Used in deriving  the Grapheme_Extend property.")]
/// <summary>Represents the Other_Grapheme_Extend property.</summary>
/// <remarks>Used in deriving the Grapheme_Extend property.</remarks>
[ValueName("Other_Grapheme_Extend"), Display(Name = "Other_Grapheme_Extend", Description = "Used in deriving the Grapheme_Extend property.")]
OtherGraphemeExtend = 0x00010000,
[ValueName("Other_ID_Continue"), Display(Name = "Other_ID_Continue", Description = "Used to maintain backward compatibility of ID_Continue.")]
/// <summary>Represents the Other_ID_Continue property.</summary>
/// <remarks>Used to maintain backward compatibility of ID_Continue.</remarks>
[ValueName("Other_ID_Continue"), Display(Name = "Other_ID_Continue", Description = "Used to maintain backward compatibility of ID_Continue.")]
OtherIdContinue = 0x00020000,
[ValueName("Other_ID_Start"), Display(Name = "Other_ID_Start", Description = "Used to maintain backward compatibility of ID_Start.")]
/// <summary>Represents the Other_ID_Start property.</summary>
/// <remarks>Used to maintain backward compatibility of ID_Start.</remarks>
[ValueName("Other_ID_Start"), Display(Name = "Other_ID_Start", Description = "Used to maintain backward compatibility of ID_Start.")]
OtherIdStart = 0x00040000,
/// <summary>Represents the Other_Lowercase property.</summary>
/// <remarks>Used in deriving the Lowercase property.</remarks>
[ValueName("Other_Lowercase"), Display(Name = "Other_Lowercase", Description = "Used in deriving the Lowercase property.")]
OtherLowercase = 0x00080000,
/// <summary>Represents the Other_Math property.</summary>
/// <remarks>Used in deriving the Math property.</remarks>
[ValueName("Other_Math"), Display(Name = "Other_Math", Description = "Used in deriving the Math property.")]
OtherMath = 0x00100000,
/// <summary>Represents the Other_Uppercase property.</summary>
/// <remarks>Used in deriving the Uppercase property.</remarks>
[ValueName("Other_Uppercase"), Display(Name = "Other_Uppercase", Description = "Used in deriving the Uppercase property.")]
OtherUppercase = 0x00200000,
/// <summary>Represents the Pattern_Syntax property.</summary>
/// <remarks>Used for pattern syntax as described in Unicode Standard Annex #31, "Unicode Identifier and Pattern Syntax" [UAX31].</remarks>
[ValueName("Pattern_Syntax"), Display(Name = "Pattern_Syntax", Description = "Used for pattern syntax as described in Unicode Standard Annex #31, \"Unicode Identifier and Pattern Syntax\" [UAX31].")]
PatternSyntax = 0x00400000,
/// <summary>Represents the Pattern_White_Space property.</summary>
[ValueName("Pattern_White_Space"), Display(Name = "Pattern_White_Space")]
PatternWhiteSpace = 0x00800000,
/// <summary>Represents the Quotation_Mark property.</summary>
/// <remarks>Punctuation characters that function as quotation marks.</remarks>
[ValueName("Quotation_Mark"), Display(Name = "Quotation_Mark", Description = "Punctuation characters that function as quotation marks.")]
QuotationMark = 0x01000000,
/// <summary>Represents the Radical property.</summary>
/// <remarks>Used in Ideographic Description Sequences.</remarks>
[ValueName("Radical"), Display(Name = "Radical", Description = "Used in Ideographic Description Sequences.")]
Radical = 0x02000000,
[ValueName("Soft_Dotted"), Display(Name = "Soft_Dotted", Description = "Characters with a \"soft dot\", like i or j. An accent placed on these characters causes the dot to disappear. An explicit dot abovecan be added where required, such as in Lithuanian.")]
/// <summary>Represents the Soft_Dotted property.</summary>
/// <remarks>Characters with a "soft dot", like i or j. An accent placed on these characters causes the dot to disappear. An explicit dot abovecan be added where required, such as in Lithuanian.</remarks>
[ValueName("Soft_Dotted"), Display(Name = "Soft_Dotted", Description = "Characters with a \"soft dot\", like i or j. An accent placed on these characters causes the dot to disappear. An explicit dot abovecan be added where required, such as in Lithuanian.")]
SoftDotted = 0x04000000,
/// <summary>Represents the STerm property.</summary>
/// <remarks>Sentence Terminal. Used in Unicode Standard Annex #29, "Unicode Text Segmentation" [UAX29].</remarks>
[ValueName("STerm"), Display(Name = "STerm", Description = "Sentence Terminal. Used in Unicode Standard Annex #29, \"Unicode Text Segmentation\" [UAX29].")]
SequenceTerminal = 0x08000000,
/// <summary>Represents the Terminal_Punctuation property.</summary>
/// <remarks>Punctuation characters that generally mark the end of textual units.</remarks>
[ValueName("Terminal_Punctuation"), Display(Name = "Terminal_Punctuation", Description = "Punctuation characters that generally mark the end of textual units.")]
TerminalPunctuation = 0x10000000,
/// <summary>Represents the Unified_Ideograph property.</summary>
/// <remarks>A property which specifies the exact set of Unified CJK Ideographs in the standard. This set excludes CJK Compatibility Ideographs (which have canonical decompositions to Unified CJK Ideographs), as well as characters from the CJK Symbols and Punctuation block. The property is used in the definition of Ideographic Description Sequences.</remarks>
[ValueName("Unified_Ideograph"), Display(Name = "Unified_Ideograph", Description = "A property which specifies the exact set of Unified CJK Ideographs in the standard. This set excludes CJK Compatibility Ideographs (which have canonical decompositions to Unified CJK Ideographs), as well as characters from the CJK Symbols and Punctuation block. The property is used in the definition of Ideographic Description Sequences.")]
UnifiedIdeograph = 0x20000000,
[ValueName("Variation_Selector"), Display(Name = "Variation_Selector", Description = "Indicates characters that are Variation Selectors. For details on the behavior of these characters, seeStandardizedVariants.html, Section 23.4, Variation Selectors in [Unicode], and Unicode Technical Standard #37, \"Unicode Ideographic Variation Database\" [UTS37].")]
/// <summary>Represents the Variation_Selector property.</summary>
/// <remarks>Indicates characters that are Variation Selectors. For details on the behavior of these characters, seeStandardizedVariants.html, Section 23.4, Variation Selectors in [Unicode], and Unicode Technical Standard #37, "Unicode Ideographic Variation Database" [UTS37].</remarks>
[ValueName("Variation_Selector"), Display(Name = "Variation_Selector", Description = "Indicates characters that are Variation Selectors. For details on the behavior of these characters, seeStandardizedVariants.html, Section 23.4, Variation Selectors in [Unicode], and Unicode Technical Standard #37, \"Unicode Ideographic Variation Database\" [UTS37].")]
VariationSelector = 0x40000000,
[ValueName("White_Space"), Display(Name = "White_Space", Description = "Spaces, separator characters and other control characters which should be treated by programming languages as \"white space\" for the purpose of parsing elements. See also Line_Break, Grapheme_Cluster_Break, Sentence_Break, and Word_Break, which classify space characters and related controls somewhat differently for particular text segmentation contexts.")]
/// <summary>Represents the White_Space property.</summary>
/// <remarks>Spaces, separator characters and other control characters which should be treated by programming languages as "white space" for the purpose of parsing elements. See also Line_Break, Grapheme_Cluster_Break, Sentence_Break, and Word_Break, which classify space characters and related controls somewhat differently for particular text segmentation contexts.</remarks>
[ValueName("White_Space"), Display(Name = "White_Space", Description = "Spaces, separator characters and other control characters which should be treated by programming languages as \"white space\" for the purpose of parsing elements. See also Line_Break, Grapheme_Cluster_Break, Sentence_Break, and Word_Break, which classify space characters and related controls somewhat differently for particular text segmentation contexts.")]
WhiteSpace = ~0x7FFFFFFF,
}
}
+24 -6
View File
@@ -1,51 +1,69 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace System.Unicode
{
/// <summary>A bitmask of the various available core properties.</summary>
/// <remarks>Core properties are normative, and derived from various properties as well as <see cref="ContributoryProperties"/>.</remarks>
[Flags]
public enum CoreProperties : int
{
// NB: Be careful when adding new properties to the enum, as EmojiProperties will be stored in the 4 upper bits out of 24.
/// <summary>Represents the Lowercase property.</summary>
[ValueName("Lowercase"), ValueName("Lower"), Display(Name = "Lowercase")]
Lowercase = 0x00000001,
/// <summary>Represents the Uppercase property.</summary>
[ValueName("Uppercase"), ValueName("Upper"), Display(Name = "Uppercase")]
Uppercase = 0x00000002,
/// <summary>Represents the Cased property.</summary>
[ValueName("Cased"), Display(Name = "Cased")]
Cased = 0x00000004,
/// <summary>Represents the Case_Ignorable property.</summary>
[ValueName("Case_Ignorable"), ValueName("CI"), Display(Name = "Case_Ignorable")]
CaseIgnorable = 0x00000008,
/// <summary>Represents the Changes_When_Lowercased property.</summary>
[ValueName("Changes_When_Lowercased"), ValueName("CWL"), Display(Name = "Changes_When_Lowercased")]
ChangesWhenLowercased = 0x00000010,
/// <summary>Represents the Changes_When_Uppercased property.</summary>
[ValueName("Changes_When_Uppercased"), ValueName("CWU"), Display(Name = "Changes_When_Uppercased")]
ChangesWhenUppercased = 0x00000020,
/// <summary>Represents the Changes_When_Titlecased property.</summary>
[ValueName("Changes_When_Titlecased"), ValueName("CWT"), Display(Name = "Changes_When_Titlecased")]
ChangesWhenTitlecased = 0x00000040,
/// <summary>Represents the Changes_When_Casefolded property.</summary>
[ValueName("Changes_When_Casefolded"), ValueName("CWCF"), Display(Name = "Changes_When_Casefolded")]
ChangesWhenCasefolded = 0x00000080,
/// <summary>Represents the Changes_When_Casemapped property.</summary>
[ValueName("Changes_When_Casemapped"), ValueName("CWCM"), Display(Name = "Changes_When_Casemapped")]
ChangesWhenCasemapped = 0x00000100,
/// <summary>Represents the Alphabetic property.</summary>
[ValueName("Alphabetic"), ValueName("Alpha"), Display(Name = "Alphabetic")]
Alphabetic = 0x00000200,
/// <summary>Represents the Default_Ignorable_Code_Point property.</summary>
[ValueName("Default_Ignorable_Code_Point"), ValueName("DI"), Display(Name = "Default_Ignorable_Code_Point")]
DefaultIgnorableCodePoint = 0x00000400,
/// <summary>Represents the Grapheme_Base property.</summary>
[ValueName("Grapheme_Base"), ValueName("Gr_Base"), Display(Name = "Grapheme_Base")]
GraphemeBase = 0x00000800,
/// <summary>Represents the Grapheme_Extend property.</summary>
[ValueName("Grapheme_Extend"), ValueName("Gr_Ext"), Display(Name = "Grapheme_Extend")]
GraphemeExtend = 0x00001000,
/// <summary>Represents the Grapheme_Link property.</summary>
[ValueName("Grapheme_Link"), ValueName("Gr_Link"), Display(Name = "Grapheme_Link")]
GraphemeLink = 0x00002000,
/// <summary>Represents the Math property.</summary>
[ValueName("Math"), Display(Name = "Math")]
Math = 0x00004000,
/// <summary>Represents the ID_Start property.</summary>
[ValueName("ID_Start"), ValueName("IDS"), Display(Name = "ID_Start")]
IdentifierStart = 0x00008000,
/// <summary>Represents the ID_Continue property.</summary>
[ValueName("ID_Continue"), ValueName("IDC"), Display(Name = "ID_Continue")]
IdentifierContinue = 0x00010000,
/// <summary>Represents the XID_Start property.</summary>
[ValueName("XID_Start"), ValueName("XIDS"), Display(Name = "XID_Start")]
ExtendedIdentifierStart = 0x00020000,
/// <summary>Represents the XID_Continue property.</summary>
[ValueName("XID_Continue"), ValueName("XIDC"), Display(Name = "XID_Continue")]
ExtendedIdentifierContinue = 0x00040000,
}
+26
View File
@@ -0,0 +1,26 @@
using System.ComponentModel.DataAnnotations;
namespace System.Unicode
{
/// <summary>A bitmask of the various available emoji properties.</summary>
/// <remarks>Emoji properties are not formally part of UCD, but .</remarks>
[Flags]
public enum EmojiProperties : byte
{
// NB: These values will be stored in as the most significant bits of CoreProperties.
// CoreProperties are stored using 18 bits out of 24 available bits, leaving at most 6 bits to use. 4 of those will be used by emoji properties.
/// <summary>Represents the Emoji property.</summary>
[ValueName("Emoji"), Display(Name = "Emoji")]
Emoji = 0x1,
/// <summary>Represents the Emoji_Presentation property.</summary>
[ValueName("Emoji_Presentation"), Display(Name = "Emoji_Presentation")]
EmojiPresentation = 0x2,
/// <summary>Represents the Emoji_Modifier_Base property.</summary>
[ValueName("Emoji_Modifier_Base"), Display(Name = "Emoji_Modifier_Base")]
EmojiModifierBase = 0x4,
/// <summary>Represents the Emoji_Component property.</summary>
[ValueName("Emoji_Component"), Display(Name = "Emoji_Component")]
EmojiComponent = 0x8,
}
}
+16 -16
View File
@@ -1,19 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
internal sealed class EnumHelper<T>
internal static class EnumHelper<T>
where T : struct
{
private static readonly Dictionary<string, T> namedValueDictionary = CreateNamedValueDictionary();
private static readonly Dictionary<T, string[]> valueNameDictionary = CreateValueNameDictionary();
private static Dictionary<string, T> CreateNamedValueDictionary()
private static Dictionary<T, string[]> CreateValueNameDictionary()
{
var type = typeof(T).GetTypeInfo();
@@ -22,15 +18,19 @@ namespace System.Unicode
return
(
from field in type.DeclaredFields
from attr in field.GetCustomAttributes<ValueNameAttribute>()
where attr.Name != null
select new KeyValuePair<string, T>(attr.Name, (T)field.GetValue(null))
).ToDictionary(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);
where field.IsPublic && field.IsLiteral
select new KeyValuePair<T, string[]>
(
(T)field.GetValue(null),
(
from attr in field.GetCustomAttributes<ValueNameAttribute>()
where attr.Name != null
select attr.Name
).ToArray()
)
).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
public static bool TryGetNamedValue(string name, out T value)
{
return namedValueDictionary.TryGetValue(name, out value);
}
public static string[] GetValueNames(T value) => valueNameDictionary.TryGetValue(value, out string[] names) ? names : null;
}
}
+2 -8
View File
@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
internal static class HangulInfo
{
@@ -55,7 +49,7 @@ namespace System.Unicode
internal static bool IsHangul(int codePoint)
{
return codePoint >= SBase && codePoint <= SBase + SCount;
return codePoint >= SBase && codePoint < SBase + SCount;
}
}
}
@@ -0,0 +1,28 @@
using System.Collections;
using System.Collections.Generic;
namespace System.Unicode
{
/// <summary>Allows enumeration of the code points contained in an encapsulated string, even when this one contains lone surrogates.</summary>
/// <remarks>
/// This enumerable will allow enumeration of UTF-16 strings containing lone surrogates.
/// For a more conformant enumeration of code points, please use <see cref="CodePointEnumerable"/> instead.
/// </remarks>
public struct PermissiveCodePointEnumerable : IEnumerable<int>
{
/// <summary>Initializes a new instance of the struct <see cref="PermissiveCodePointEnumerable"/>.</summary>
/// <param name="text">The string whose code points must be enumerated.</param>
public PermissiveCodePointEnumerable(string text) => Text = text ?? throw new ArgumentNullException(nameof(text));
/// <summary>Gets the text whose code points are being enumerated.</summary>
public string Text { get; }
/// <summary>Gets an enumerator which can be used to enumerate the code points in the text.</summary>
/// <returns></returns>
public PermissiveCodePointEnumerator GetEnumerator() => new PermissiveCodePointEnumerator(Text);
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
@@ -0,0 +1,69 @@
using System.Collections;
using System.Collections.Generic;
namespace System.Unicode
{
/// <summary>Supports a permissive iteration of code points in a <see cref="string"/>.</summary>
public struct PermissiveCodePointEnumerator : IEnumerator<int>
{
private readonly string text;
private int current;
private int index;
/// <summary>Initializes a new instance of the <see cref="PermissiveCodePointEnumerator"/> struct.</summary>
/// <param name="text">The text whose code point should be enumerated.</param>
/// <exception cref="ArgumentNullException"><paramref cref="text"/> is <see langword="null"/>.</exception>
public PermissiveCodePointEnumerator(string text)
{
if (text == null) throw new ArgumentNullException(nameof(text));
this.text = text;
this.current = 0;
this.index = -1;
}
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public int Current { get { return current; } }
object IEnumerator.Current { get { return current; } }
void IDisposable.Dispose() { }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns><see langword="true"/> if the enumerator was successfully advanced to the next element; <see langword="false"/> if the enumerator has passed the end of the collection.</returns>
public bool MoveNext()
{
if (index < text.Length && (index += current > 0xFFFF ? 2 : 1) < text.Length)
{
current = GetUtf32(text, index);
return true;
}
else
{
current = 0;
return false;
}
}
void IEnumerator.Reset()
{
current = 0;
index = -1;
}
private static int GetUtf32(string s, int index)
{
char c1 = s[index];
if (char.IsHighSurrogate(c1) && ++index < s.Length)
{
char c2 = s[index];
if (char.IsLowSurrogate(c2)) return char.ConvertToUtf32(c1, c2);
}
return c1;
}
}
}
@@ -1,10 +1,5 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
[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")]
+21 -7
View File
@@ -1,16 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Contains extension methods applicable to the <see cref="string"/> type.</summary>
public static class StringExtensions
{
/// <summary>Encapsulates the string in an object which can be used to enumerate code points.</summary>
/// <remarks>
/// The enumerable returned by this method enumerates code points in a strict manner.
/// If the string contains lone surrogates, the enumeration will throw.
/// </remarks>
/// <param name="s">The string to encapsulate.</param>
/// <returns>An enumerable object, which can be used to enumerate code points in the string.</returns>
public static CodePointEnumerable AsCodePointEnumerable(this string s)
{
return new CodePointEnumerable(s);
}
/// <summary>Encapsulates the string in an object which can be used to enumerate code points in a permissive way.</summary>
/// <remarks>
/// The enumerable returned by this method is permissive, regarding the code points represented.
/// It allows invalid sequences, such as lone surrogates, the enumeration will handle those gracefully.
/// </remarks>
/// <param name="s">The string to encapsulate.</param>
/// <returns>An enumerable object, which can be used to enumerate code points in the string.</returns>
public static PermissiveCodePointEnumerable AsPermissiveCodePointEnumerable(this string s)
{
return new PermissiveCodePointEnumerable(s);
}
}
}
+2 -8
View File
@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Represents the fields available for an UCD entry.</summary>
/// <remarks>Not all the enumeration member directly map to a field.</remarks>
@@ -34,7 +28,7 @@ namespace System.Unicode
SimpleTitleCaseMapping = 4096,
ContributoryProperties = 8192,
CoreProperties = 16384,
CorePropertiesAndEmojiProperties = 16384,
CrossRerefences = 32768,
}
+7 -7
View File
@@ -1,20 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace System.Unicode
{
/// <summary>Represents a Unicode block.</summary>
[DebuggerDisplay("[{CodePointRange.ToString(),nq}] {Name,nq}")]
public struct UnicodeBlock
{
/// <summary>The code point range of this block.</summary>
public readonly UnicodeCodePointRange CodePointRange;
/// <summary>The name of this block.</summary>
public readonly string Name;
internal UnicodeBlock(UnicodeCodePointRange codePointRange, string name)
{
this.CodePointRange = codePointRange;
this.Name = name;
CodePointRange = codePointRange;
Name = name;
}
}
}
@@ -1,19 +1,21 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
namespace System.Unicode
{
/// <summary>Provides extensions to the <see cref="UnicodeCategory"/> type.</summary>
public static class UnicodeCategoryExtensions
{
/// <summary>Gets the short name of the unicode category.</summary>
/// <param name="category">The category whose short name should be retrieved.</param>
/// <returns>The short name of the unicode category.</returns>
public static string GetShortName(this UnicodeCategory category)
{
return UnicodeCategoryInfo.Get(category).ShortName;
}
/// <summary>Gets the long name of the unicode category.</summary>
/// <param name="category">The category whose long name should be retrieved.</param>
/// <returns>The long name of the unicode category.</returns>
public static string GetLongName(this UnicodeCategory category)
{
return UnicodeCategoryInfo.Get(category).LongName;
+38 -40
View File
@@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Provides complementary information on <see cref="UnicodeCategory"/> values.</summary>
public struct UnicodeCategoryInfo : IEquatable<UnicodeCategoryInfo>
{
private static readonly UnicodeCategoryInfo[] categories =
@@ -80,55 +77,56 @@ namespace System.Unicode
return unicodeLongNameToCategoryDictionary[name];
}
public static UnicodeCategoryInfo Get(UnicodeCategory category)
{
return categories[(int)category];
}
/// <summary>Gets an <see cref="UnicodeCategoryInfo"/> value providing information on the specified unicode category.</summary>
/// <param name="category">The category on which information should be retrieved.</param>
/// <returns>Information on the specified category.</returns>
public static UnicodeCategoryInfo Get(UnicodeCategory category) => categories[(int)category];
public static UnicodeCategoryInfo FromShortName(string name)
{
return Get(GetCategoryFromShortName(name));
}
/// <summary>Gets an <see cref="UnicodeCategoryInfo"/> value providing information on the unicode category, accessed by its short name, as per the Unicode standard.</summary>
/// <param name="name">The short name for which information should be retrieved .</param>
/// <returns>Information on the specified category.</returns>
public static UnicodeCategoryInfo FromShortName(string name) => Get(GetCategoryFromShortName(name));
public static UnicodeCategoryInfo FromLongName(string name)
{
return Get(GetCategoryFromLongName(name));
}
/// <summary>Gets an <see cref="UnicodeCategoryInfo"/> value providing information on the unicode category, accessed by its long name, as per the Unicode standard.</summary>
/// <param name="name">The long name for which information should be retrieved .</param>
/// <returns>Information on the specified category.</returns>
public static UnicodeCategoryInfo FromLongName(string name) => Get(GetCategoryFromLongName(name));
/// <summary>The unicode category described.</summary>
public readonly UnicodeCategory Category;
/// <summary>Short name of the category, as per the Unicode standard.</summary>
public readonly string ShortName;
/// <summary>Long name of the category, as per the Unicode standard.</summary>
public readonly string LongName;
private UnicodeCategoryInfo(UnicodeCategory category, string shortName, string longName)
{
this.Category = category;
this.ShortName = shortName;
this.LongName = longName;
Category = category;
ShortName = shortName;
LongName = longName;
}
public override string ToString()
{
return Category.ToString();
}
/// <summary>Returns a <see cref="string" /> that represents this instance.</summary>
/// <returns>A <see cref="string" /> that represents this instance.</returns>
public override string ToString() => Category.ToString();
public override bool Equals(object obj)
{
return obj is UnicodeCategoryInfo && Equals((UnicodeCategoryInfo)obj);
}
/// <summary>Determines whether the specified <see cref="object" />, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object" /> to compare with this instance.</param>
/// <returns><see langword="true" /> if the specified <see cref="object" /> is equal to this instance; otherwise, <see langword="false" />.</returns>
public override bool Equals(object obj) => obj is UnicodeCategoryInfo && Equals((UnicodeCategoryInfo)obj);
public bool Equals(UnicodeCategoryInfo other)
{
return other.Category == Category && (other.Category != 0 || other.ShortName != null);
}
/// <summary>Indicates whether the current object is equal to another object of the same type.</summary>
/// <param name="other">An object to compare with this object.</param>
/// <returns><see langword="true" /> if the current object is equal to the other parameter; otherwise, <see langword="false" />.</returns>
public bool Equals(UnicodeCategoryInfo other) => other.Category == Category && (other.Category != 0 || other.ShortName != null);
public override int GetHashCode()
{
return (int)Category;
}
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() => (int)Category;
public static implicit operator UnicodeCategory(UnicodeCategoryInfo info)
{
return info.Category;
}
/// <summary>Performs an implicit conversion from <see cref="UnicodeCategoryInfo"/> to <see cref="UnicodeCategory"/>.</summary>
/// <param name="info">The information.</param>
/// <returns>The result of the conversion.</returns>
public static implicit operator UnicodeCategory(UnicodeCategoryInfo info) => info.Category;
}
}
+171 -42
View File
@@ -1,88 +1,217 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Provides information on a specific unicode code point.</summary>
[DebuggerDisplay(@"{CodePoint.ToString(""X4""),nq} - {Name,nq}")]
public struct UnicodeCharInfo
{
/// <summary>The code point.</summary>
private readonly int codePoint;
/// <summary>The name of the code point.</summary>
private readonly string name;
private readonly UnicodeCharacterData unicodeCharacterData;
private readonly UnihanCharacterData unihanCharacterData;
internal readonly int unicodeCharacterDataIndex;
private readonly int unihanCharacterDataIndex;
private readonly string block;
public int CodePoint { get { return codePoint; } }
private ref UnicodeCharacterData UnicodeCharacterData => ref UnicodeInfo.GetUnicodeCharacterData(unicodeCharacterDataIndex);
private ref UnihanCharacterData UnihanCharacterData => ref UnicodeInfo.GetUnihanCharacterData(unihanCharacterDataIndex);
/// <summary>Gets the code point as an UTF-32 value.</summary>
public int CodePoint => codePoint;
/// <summary>Gets the code point name.</summary>
/// <remarks>This is the Name Unicode property.</remarks>
[ValueName("Name"), ValueName("na")]
public string Name { get { return name; } }
public string Name => name;
/// <summary>Gets the name aliases defined for the code point.</summary>
/// <remarks>This is the Name_Alias Unicode property.</remarks>
[ValueName("Name_Alias")]
public UnicodeNameAliasCollection NameAliases { get { return new UnicodeNameAliasCollection(unicodeCharacterData?.NameAliases); } }
public UnicodeNameAliasCollection NameAliases => new UnicodeNameAliasCollection(UnicodeCharacterData.NameAliases);
/// <summary>Gets the category defined for the code point.</summary>
/// <remarks>This is the General_Category Unicode property.</remarks>
[ValueName("General_Category"), ValueName("gc")]
public UnicodeCategory Category { get { return unicodeCharacterData?.Category ?? UnicodeCategory.OtherNotAssigned; } }
public UnicodeCategory Category => UnicodeCharacterData.Category;
/// <summary>Gets the name of the block where the code point is located.</summary>
/// <remarks>This is the Block Unicode property.</remarks>
[ValueName("Block"), ValueName("blk")]
public string Block { get { return block ?? UnicodeInfo.DefaultBlock; } }
public string Block => block ?? UnicodeInfo.DefaultBlock;
/// <summary>Gets the canonical combining class defined for the code point.</summary>
/// <remarks>This is the Canonical_Combining_Class Unicode property.</remarks>
[ValueName("Canonical_Combining_Class"), ValueName("ccc")]
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData?.CanonicalCombiningClass ?? CanonicalCombiningClass.NotReordered; } }
public CanonicalCombiningClass CanonicalCombiningClass => UnicodeCharacterData.CanonicalCombiningClass;
/// <summary>Gets the bidirectional class defined for the code point.</summary>
/// <remarks>This is the Bidi_Class Unicode property.</remarks>
[ValueName("Bidi_Class"), ValueName("bc")]
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData?.BidirectionalClass ?? BidirectionalClass.LeftToRight; } }
public BidirectionalClass BidirectionalClass => UnicodeCharacterData.BidirectionalClass;
/// <summary>Gets the decomposition type defined for the code point.</summary>
/// <remarks>This is the Decomposition_Type Unicode property.</remarks>
[ValueName("Decomposition_Type"), ValueName("dt")]
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData?.DecompositionType ?? CompatibilityFormattingTag.Canonical; } }
public CompatibilityFormattingTag DecompositionType => UnicodeCharacterData.DecompositionType;
/// <summary>Gets the decomposition mapping defined for the code point.</summary>
/// <remarks>This is the Decomposition_Mapping Unicode property.</remarks>
[ValueName("Decomposition_Mapping"), ValueName("dm")]
public string DecompositionMapping { get { return unicodeCharacterData?.DecompositionMapping; } }
public string DecompositionMapping => UnicodeCharacterData.DecompositionMapping;
/// <summary>Gets the numeric type defined for the code point.</summary>
/// <remarks>
/// This is the Numeric_Type Unicode property.
/// When this value is defined to something other than <see cref="UnicodeNumericType.None"/>, the <see cref="NumericValue"/> indicates the numeric value of the code point.
/// The value of this property may be influenced by Unihan data, which will set it to <see cref="UnicodeNumericType.Numeric"/>.
/// In this case, the property <see cref="UnihanNumericType"/> will indicate the origin of the numeric value in Unihan data.
/// </remarks>
[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 UnicodeNumericType NumericType => unihanCharacterDataIndex >= 0 ? UnihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : UnicodeCharacterData.NumericType;
/// <summary>Gets the Unihan numeric type defined for the code point.</summary>
/// <remarks>The value of this property indicates which of the kPrimaryNumeric, kAccountingNumeric, or kOtherNumeric Unihan property is set, if any.</remarks>
public UnihanNumericType UnihanNumericType => unihanCharacterDataIndex >= 0 ? UnihanCharacterData.NumericType : UnihanNumericType.None;
/// <summary>Gets the numeric value defined for the code point.</summary>
/// <remarks>
/// This is the Numeric_Value Unicode property.
/// This value may come from Unihan data.
/// When this property set, the <see cref="NumericType"/> and <see cref="UnihanNumericType"/> indicates the nature of the numeric value.
/// </remarks>
[ValueName("Numeric_Value"), ValueName("nv")]
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData?.NumericValue; } }
public UnicodeRationalNumber? NumericValue
{
get
{
if (unihanCharacterDataIndex >= 0)
{
ref var unihanCharacterData = ref UnihanCharacterData;
if (unihanCharacterData.NumericType != UnihanNumericType.None)
{
return new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1);
}
}
return UnicodeCharacterData.NumericValue;
}
}
/// <summary>Gets a value indicating whether the character is mirrored in bidirectional text.</summary>
/// <remarks>This is the Bidi_Mirrored Unicode property.</remarks>
[ValueName("Bidi_Mirrored")]
public bool BidirectionalMirrored { get { return unicodeCharacterData?.BidirectionalMirrored ?? false; } }
public bool BidirectionalMirrored => UnicodeCharacterData.BidirectionalMirrored;
/// <summary>Gets the Unicode 1 name of the code point.</summary>
/// <remarks>This is the Unicode_1_Name Unicode property.</remarks>
[ValueName("Unicode_1_Name"), ValueName("na1")]
public string OldName { get { return unicodeCharacterData?.OldName; } }
public string OldName => UnicodeCharacterData.OldName;
/// <summary>Gets the simple uppercase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Uppercase_Mapping Unicode property.</remarks>
[ValueName("Simple_Uppercase_Mapping"), ValueName("suc")]
public string SimpleUpperCaseMapping { get { return unicodeCharacterData?.SimpleUpperCaseMapping; } }
public string SimpleUpperCaseMapping => UnicodeCharacterData.SimpleUpperCaseMapping;
/// <summary>Gets the simple lowercase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Lowercase_Mapping Unicode property.</remarks>
[ValueName("Simple_Lowercase_Mapping"), ValueName("slc")]
public string SimpleLowerCaseMapping { get { return unicodeCharacterData?.SimpleLowerCaseMapping; } }
public string SimpleLowerCaseMapping => UnicodeCharacterData.SimpleLowerCaseMapping;
/// <summary>Gets the simple titlecase mapping defined for the code point.</summary>
/// <remarks>This is the Simple_Titlecase_Mapping Unicode property.</remarks>
[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); } }
public string SimpleTitleCaseMapping => UnicodeCharacterData.SimpleTitleCaseMapping;
/// <summary>Gets a value indicating which of the boolean contributory properties are defined for the code point.</summary>
/// <remarks>
/// The Unicode standard indicates contributory properties as neither normative nor informational.
/// However, contributory properties are used by Unicode to define the code properties.
/// The corresponding core properties may be accessed from the <see cref="CoreProperties"/> member.
/// </remarks>
public ContributoryProperties ContributoryProperties => UnicodeCharacterData.ContributoryProperties;
/// <summary>Gets a value indicating which of the boolean core properties are defined for the code point.</summary>
/// <remarks>The core properties are computed by combining various character information together with contributory properties.</remarks>
public CoreProperties CoreProperties => UnicodeCharacterData.CoreProperties;
/// <summary>Gets a value indicating which of the boolean emoji properties are defined for the code point.</summary>
/// <remarks>The emoji properties are provided by the Unicode Emoji standard, which is not directly part of UCD.</remarks>
public EmojiProperties EmojiProperties => UnicodeCharacterData.EmojiProperties;
/// <summary>Gets a collection of cross references associated with the code point.</summary>
/// <remarks>The cross references have been extracted from Unicode data but are not normative.</remarks>
public UnicodeCrossReferenceCollection CrossRerefences => new UnicodeCrossReferenceCollection(UnicodeCharacterData.CrossRerefences);
/// <summary>Gets the radical and stroke count for the code point.</summary>
/// <remarks>
/// This is the Unicode_Radical_Stroke Unicode property, defined as kRSUnicode in Unihan data.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kRSUnicode"), ValueName("cjkRSUnicode"), ValueName("Unicode_Radical_Stroke"), ValueName("URS")]
public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts { get { return new UnicodeRadicalStrokeCountCollection(unihanCharacterData?.UnicodeRadicalStrokeCounts); } }
public UnicodeRadicalStrokeCountCollection UnicodeRadicalStrokeCounts => new UnicodeRadicalStrokeCountCollection(UnihanCharacterData.UnicodeRadicalStrokeCounts);
/// <summary>Gets the definition of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kDefinition Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kDefinition")]
public string Definition { get { return unihanCharacterData?.Definition; } }
public string Definition => UnihanCharacterData.Definition;
/// <summary>Gets the Mandarin reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kMandarin Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kMandarin")]
public string MandarinReading { get { return unihanCharacterData?.MandarinReading; } }
public string MandarinReading => UnihanCharacterData.MandarinReading;
/// <summary>Gets the Cantonese reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kCantonese Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kCantonese")]
public string CantoneseReading { get { return unihanCharacterData?.CantoneseReading; } }
public string CantoneseReading => UnihanCharacterData.CantoneseReading;
/// <summary>Gets the Japanese Kun reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kJapaneseKun Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kJapaneseKun")]
public string JapaneseKunReading { get { return unihanCharacterData?.JapaneseKunReading; } }
public string JapaneseKunReading => UnihanCharacterData.JapaneseKunReading;
/// <summary>Gets the Japanese On reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kJapaneseOn Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kJapaneseOn")]
public string JapaneseOnReading { get { return unihanCharacterData?.JapaneseOnReading; } }
public string JapaneseOnReading => UnihanCharacterData.JapaneseOnReading;
/// <summary>Gets the Korean reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kKorean Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kKorean")]
public string KoreanReading { get { return unihanCharacterData?.KoreanReading; } }
public string KoreanReading => UnihanCharacterData.KoreanReading;
/// <summary>Gets the Hangul reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kHangul Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kHangul")]
public string HangulReading { get { return unihanCharacterData?.HangulReading; } }
public string HangulReading => UnihanCharacterData.HangulReading;
/// <summary>Gets the Vietnamese reading of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kVietnamese Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kVietnamese")]
public string VietnameseReading { get { return unihanCharacterData?.VietnameseReading; } }
public string VietnameseReading => UnihanCharacterData.VietnameseReading;
/// <summary>Gets the simplified variant of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kSimplifiedVariant Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kSimplifiedVariant")]
public string SimplifiedVariant { get { return unihanCharacterData?.SimplifiedVariant; } }
public string SimplifiedVariant => UnihanCharacterData.SimplifiedVariant;
/// <summary>Gets the traditional variant of the character from the Unihan data.</summary>
/// <remarks>
/// This is the kTraditionalVariant Unicode property.
/// This property is only ever useful when the character is a CJK ideograph.
/// </remarks>
[ValueName("kTraditionalVariant")]
public string TraditionalVariant { get { return unihanCharacterData?.TraditionalVariant; } }
public string TraditionalVariant => UnihanCharacterData.TraditionalVariant;
internal UnicodeCharInfo(int codePoint, UnicodeCharacterData unicodeCharacterData, UnihanCharacterData unihanCharacterData, string block)
internal UnicodeCharInfo(int codePoint, int unicodeCharacterDataIndex, int unihanCharacterDataIndex, string block)
{
this.codePoint = codePoint;
this.name = UnicodeInfo.GetName(codePoint, unicodeCharacterData);
this.unicodeCharacterData = unicodeCharacterData;
this.unihanCharacterData = unihanCharacterData;
this.name = unicodeCharacterDataIndex >= 0 ? UnicodeInfo.GetName(codePoint, ref UnicodeInfo.GetUnicodeCharacterData(unicodeCharacterDataIndex)) : null;
this.unicodeCharacterDataIndex = unicodeCharacterDataIndex;
this.unihanCharacterDataIndex = unihanCharacterDataIndex;
this.block = block;
}
}
+8 -11
View File
@@ -1,13 +1,8 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
namespace System.Unicode
{
internal sealed class UnicodeCharacterData
internal struct UnicodeCharacterData
{
public readonly UnicodeCodePointRange CodePointRange;
public readonly string Name;
@@ -25,7 +20,9 @@ namespace System.Unicode
public readonly string SimpleLowerCaseMapping;
public readonly string SimpleTitleCaseMapping;
public readonly ContributoryProperties ContributoryProperties;
public readonly CoreProperties CoreProperties;
private readonly int corePropertiesAndEmojiProperties;
public CoreProperties CoreProperties => (CoreProperties)(corePropertiesAndEmojiProperties & 0x000FFFFF);
public EmojiProperties EmojiProperties => (EmojiProperties)(corePropertiesAndEmojiProperties >> 20);
public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
@@ -47,7 +44,7 @@ namespace System.Unicode
string simpleLowerCaseMapping,
string simpleTitleCaseMapping,
ContributoryProperties contributoryProperties,
CoreProperties coreProperties,
int corePropertiesAndEmojiProperties,
int[] crossRerefences
)
{
@@ -67,10 +64,10 @@ namespace System.Unicode
this.SimpleLowerCaseMapping = simpleLowerCaseMapping;
this.SimpleTitleCaseMapping = simpleTitleCaseMapping;
this.ContributoryProperties = contributoryProperties;
this.CoreProperties = coreProperties;
this.corePropertiesAndEmojiProperties = corePropertiesAndEmojiProperties;
this.CrossRerefences = crossRerefences;
}
public UnicodeRationalNumber? NumericValue { get { return NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?; } }
public UnicodeRationalNumber? NumericValue => NumericType != UnicodeNumericType.None ? numericValue : null as UnicodeRationalNumber?;
}
}
+41 -7
View File
@@ -1,21 +1,22 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Represents a range of Unicode code points.</summary>
public struct UnicodeCodePointRange : IEnumerable<int>
{
/// <summary>Represents an enumerator which enumerated through all the code points in the <see cref="UnicodeCodePointRange"/>.</summary>
public struct Enumerator : IEnumerator<int>
{
private readonly int start;
private readonly int end;
private int index;
/// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct.</summary>
/// <param name="start">The start of the range.</param>
/// <param name="end">The end of the range.</param>
internal Enumerator(int start, int end)
{
this.start = start;
@@ -23,22 +24,34 @@ namespace System.Unicode
this.index = start - 1;
}
/// <summary>Does nothing.</summary>
public void Dispose() { }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public int Current { get { return index; } }
object IEnumerator.Current { get { return index; } }
void IDisposable.Dispose() { }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
public bool MoveNext() { return index < end && ++index == index; }
void IEnumerator.Reset() { index = start - 1; }
}
/// <summary>The first code point in the range.</summary>
public readonly int FirstCodePoint;
/// <summary>The last code point in the range.</summary>
public readonly int LastCodePoint;
/// <summary>Gets a value indicating whether this value represents a single code point.</summary>
/// <value><see langword="true" /> if this value represents a single code point; otherwise, <see langword="false" />.</value>
public bool IsSingleCodePoint { get { return FirstCodePoint == LastCodePoint; } }
/// <summary>Initializes a new instance of the <see cref="UnicodeCodePointRange"/> struct for a single code point.</summary>
/// <param name="codePoint">The code point.</param>
/// <exception cref="System.ArgumentOutOfRangeException"></exception>
public UnicodeCodePointRange(int codePoint)
{
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(codePoint));
@@ -47,6 +60,13 @@ namespace System.Unicode
LastCodePoint = codePoint;
}
/// <summary>Initializes a new instance of the <see cref="UnicodeCodePointRange"/> struct with specified bounds.</summary>
/// <param name="firstCodePoint">The first code point in the range.</param>
/// <param name="lastCodePoint">The last code point in the range.</param>
/// <exception cref="System.ArgumentOutOfRangeException">
/// <paramref name="firstCodePoint"/> is less than 0 or greated than 0x10FFFF,
/// or <paramref name="lastCodePoint"/> is less than <paramref name="firstCodePoint"/> or greated than 0x10FFFF.
/// </exception>
public UnicodeCodePointRange(int firstCodePoint, int lastCodePoint)
{
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(firstCodePoint));
@@ -56,8 +76,13 @@ namespace System.Unicode
LastCodePoint = lastCodePoint;
}
/// <summary>Determines whether the range contains the specific code point.</summary>
/// <remarks>This method does not validate its inputs, but will always return <see langword="false"/> for any invalid code point.</remarks>
/// <param name="i">The integer to check against the range.</param>
/// <returns><see langword="true"/> if the range contains the specified code point; otherwise, <see langword="false"/>.</returns>
public bool Contains(int i)
{
// Since the first and last code points have been checked or are at their default value of zero, the method will always exlcude invalid code points.
return i >= FirstCodePoint & i <= LastCodePoint;
}
@@ -66,11 +91,18 @@ namespace System.Unicode
return FirstCodePoint <= codePoint ? LastCodePoint < codePoint ? 1 : 0 : -1;
}
/// <summary>Returns a <see cref="System.String" /> that represents this instance.</summary>
/// <returns>A <see cref="System.String" /> that represents this instance.</returns>
public override string ToString()
{
return FirstCodePoint == LastCodePoint ? FirstCodePoint.ToString("X4") : FirstCodePoint.ToString("X4") + ".." + LastCodePoint.ToString("X4");
}
/// <summary>Parses the specified into a <see cref="UnicodeCodePointRange"/>.</summary>
/// <remarks>Code point ranges are encoded as one unprefixed hexadecimal number for single code points, or a pair of unprefixed hexadecimal numbers separated by the characters "..".</remarks>
/// <param name="s">The text to parse.</param>
/// <returns>The parsed <see cref="UnicodeCodePointRange"/> value.</returns>
/// <exception cref="System.FormatException">The parameter <paramref name="s"/> was not in an allowed format.</exception>
public static UnicodeCodePointRange Parse(string s)
{
int start, end;
@@ -91,6 +123,8 @@ namespace System.Unicode
return new UnicodeCodePointRange(start, end);
}
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>A <see cref="Enumerator"/> that can be used to iterate through the collection.</returns>
public Enumerator GetEnumerator() { return new Enumerator(FirstCodePoint, LastCodePoint); }
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
@@ -7,36 +7,51 @@ using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Represents a collection of code point cross-references.</summary>
public struct UnicodeCrossReferenceCollection : IList<int>
{
private static int[] EmptyArray = new int[0];
/// <summary>Represents an enumerator for the <see cref="UnicodeCrossReferenceCollection"/> class.</summary>
public struct Enumerator : IEnumerator<int>
{
private readonly int[] items;
private int index;
/// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct.</summary>
/// <param name="items">The items to enumerate.</param>
internal Enumerator(int[] items)
{
this.items = items;
this.index = -1;
}
/// <summary>Does nothing.</summary>
public void Dispose() { }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public int Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
/// <summary>Gets an empty <see cref="UnicodeCrossReferenceCollection"/> struct.</summary>
public static readonly UnicodeCrossReferenceCollection Empty = new UnicodeCrossReferenceCollection(EmptyArray);
private readonly int[] items;
public UnicodeCrossReferenceCollection() { items = EmptyArray; }
internal UnicodeCrossReferenceCollection(int[] items) { this.items = items ?? EmptyArray; }
/// <summary>Gets the cross-referenced code point at the specified index.</summary>
/// <value>The cross-referenced code point.</value>
/// <param name="index">The index.</param>
/// <returns>The cross-referenced code point at the specified index.</returns>
public int this[int index] { get { return items[index]; } }
int IList<int>.this[int index]
@@ -45,23 +60,39 @@ namespace System.Unicode
set { throw new NotSupportedException(); }
}
/// <summary>Gets the number of elements contained in the <see cref="UnicodeCrossReferenceCollection"/>.</summary>
/// <value>The number of elements contained in the <see cref="UnicodeCrossReferenceCollection"/>.</value>
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(); }
void ICollection<int>.Add(int item) { throw new NotSupportedException(); }
void IList<int>.Insert(int index, int item) { throw new NotSupportedException(); }
public bool Remove(int item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
bool ICollection<int>.Remove(int item) { throw new NotSupportedException(); }
void IList<int>.RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
void ICollection<int>.Clear() { throw new NotSupportedException(); }
/// <summary>Determines the index of a specific item in the <see cref="UnicodeCrossReferenceCollection"/>.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeCrossReferenceCollection"/>.</param>
/// <returns>The index of the item if found in the list; otherwise, -1.</returns>
public int IndexOf(int item) { return Array.IndexOf(items, item); }
/// <summary>Determines whether the <see cref="UnicodeCrossReferenceCollection"/> contains a specific value.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeCrossReferenceCollection"/>.</param>
/// <returns><see langword="true" /> if item is fount in the <see cref="UnicodeCrossReferenceCollection"/>; <see langword="false" /> otherwise.</returns>
public bool Contains(int item) { return IndexOf(item) >= 0; }
/// <summary>
/// Copies the elements of the UnicodeCrossReferenceCollection to an <see cref="System.Array" />, starting at a particular <see cref="System.Array" /> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="System.Array" /> that is the destination of the elements to copy from UnicodeCrossReferenceCollection. The <see cref="System.Array" /> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zeo-based index in array at which copy begins.</param>
public void CopyTo(int[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>A <see cref="Enumerator"/> that can be used to iterate through the collection.</returns>
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
+95 -84
View File
@@ -1,17 +1,21 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Provides access to unicode information.</summary>
public static class UnicodeInfo
{
// NB: These fields will be used as a default value for UnicodeCharacterData and UnihanCharacterData, and passed by reference.
// They should be considered as being redonly, even if they aren't explicitely.
private static /*readonly*/ UnicodeCharacterData DefaultUnicodeCharacterData = new UnicodeCharacterData(default(UnicodeCodePointRange), null, null, UnicodeCategory.OtherNotAssigned, 0, 0, 0, null, 0, default(UnicodeRationalNumber), false, null, null, null, null, 0, 0, null);
private static /*readonly*/ UnihanCharacterData DefaultUnihanCharacterData = default(UnihanCharacterData);
/// <summary>The block name returned when no block is assigned to a specific code point.</summary>
public const string DefaultBlock = "No_Block";
private static readonly Version unicodeVersion;
@@ -20,6 +24,7 @@ namespace System.Unicode
private static readonly UnicodeBlock[] blocks;
private static readonly CjkRadicalData[] radicals;
private static readonly int maxContiguousIndex;
private static readonly string[] emojiSequences;
static UnicodeInfo()
{
@@ -42,17 +47,21 @@ namespace System.Unicode
byte formatVersion = reader.ReadByte();
if (formatVersion != 1) throw new InvalidDataException();
if (formatVersion != 2) throw new InvalidDataException();
var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte());
var fileUnicodeVersion = new Version(reader.ReadUInt16(), reader.ReadByte(), reader.ReadByte());
var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)];
var unicodeCharacterDataEntries = new UnicodeCharacterData[ReadCodePoint(reader)]; // Allocate one extra entry to act as a dummy entry.
byte[] nameBuffer = new byte[128];
int mci = 0;
for (i = 0; i < unicodeCharacterDataEntries.Length; ++i)
{
if ((unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer)).CodePointRange.Contains(i)) mci = i;
ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
if (unicodeCharacterDataEntries[i].CodePointRange.Contains(i))
{
mci = i;
}
else
{
++i;
@@ -64,28 +73,28 @@ namespace System.Unicode
for (; i < unicodeCharacterDataEntries.Length; ++i)
{
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader, nameBuffer);
ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
}
var blockEntries = new UnicodeBlock[reader.ReadByte()];
var blockEntries = new UnicodeBlock[reader.ReadUInt16()];
for (i = 0; i < blockEntries.Length; ++i)
{
blockEntries[i] = ReadBlockEntry(reader);
ReadBlockEntry(reader, out blockEntries[i]);
}
var cjkRadicalEntries = new CjkRadicalData[reader.ReadByte()];
for (i = 0; i < cjkRadicalEntries.Length; ++i)
{
cjkRadicalEntries[i] = ReadCjkRadicalInfo(reader);
}
ReadCjkRadicalInfo(reader, out cjkRadicalEntries[i]);
}
var unihanCharacterDataEntries = new UnihanCharacterData[ReadCodePoint(reader)];
for (i = 0; i < unihanCharacterDataEntries.Length; ++i)
{
unihanCharacterDataEntries[i] = ReadUnihanCharacterDataEntry(reader);
ReadUnihanCharacterDataEntry(reader, out unihanCharacterDataEntries[i]);
}
unicodeVersion = fileUnicodeVersion;
@@ -96,7 +105,7 @@ namespace System.Unicode
}
}
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer)
private static void ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer, out UnicodeCharacterData value)
{
var fields = (UcdFields)reader.ReadUInt16();
@@ -151,7 +160,7 @@ namespace System.Unicode
string simpleLowerCaseMapping = (fields & UcdFields.SimpleLowerCaseMapping) != 0 ? reader.ReadString() : null;
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 corePropertiesAndEmojiProperties = (fields & UcdFields.CorePropertiesAndEmojiProperties) != 0 ? ReadInt24(reader) : 0;
int[] crossReferences = (fields & UcdFields.CrossRerefences) != 0 ? new int[reader.ReadByte() + 1] : null;
if (crossReferences != null)
@@ -160,7 +169,7 @@ namespace System.Unicode
crossReferences[i] = ReadCodePoint(reader);
}
return new UnicodeCharacterData
value = new UnicodeCharacterData
(
codePointRange,
name,
@@ -178,12 +187,12 @@ namespace System.Unicode
simpleLowerCaseMapping,
simpleTitleCaseMapping,
contributoryProperties,
coreProperties,
corePropertiesAndEmojiProperties,
crossReferences
);
}
private static UnihanCharacterData ReadUnihanCharacterDataEntry(BinaryReader reader)
private static void ReadUnihanCharacterDataEntry(BinaryReader reader, out UnihanCharacterData value)
{
var fields = (UnihanFields)reader.ReadUInt16();
@@ -217,7 +226,7 @@ namespace System.Unicode
string simplifiedVariant = (fields & UnihanFields.SimplifiedVariant) != 0 ? reader.ReadString() : null;
string traditionalVariant = (fields & UnihanFields.TraditionalVariant) != 0 ? reader.ReadString() : null;
return new UnihanCharacterData
value = new UnihanCharacterData
(
codePoint,
numericType,
@@ -236,7 +245,7 @@ namespace System.Unicode
);
}
private static CjkRadicalData ReadCjkRadicalInfo(BinaryReader reader)
private static void ReadCjkRadicalInfo(BinaryReader reader, out CjkRadicalData value)
{
char tr;
char tc;
@@ -244,18 +253,15 @@ namespace System.Unicode
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());
value = (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 UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
}
private static void ReadBlockEntry(BinaryReader reader, out UnicodeBlock value)
=> value = new UnicodeBlock(new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
private static int ReadInt24(BinaryReader reader)
{
return reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
}
private static int ReadInt24(BinaryReader reader) => reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
#if DEBUG
internal static int ReadCodePoint(BinaryReader reader)
@@ -280,23 +286,15 @@ namespace System.Unicode
}
}
/// <summary>Gets the version of the Unicode standard supported by the class.</summary>
public static Version UnicodeVersion { get { return unicodeVersion; } }
private static UnicodeCharacterData FindUnicodeCodePoint(int codePoint)
{
// 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 int FindUnicodeCodePointIndex(int codePoint)
=> codePoint <= maxContiguousIndex ?
codePoint : // 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.
BinarySearchUnicodeCodePointIndex(codePoint); // For other code points, we will use a classic binary search with adjusted search indexes.
private static UnicodeCharacterData BinarySearchUnicodeCodePoint(int codePoint)
private static int BinarySearchUnicodeCodePointIndex(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.
@@ -309,22 +307,22 @@ namespace System.Unicode
int Δ = unicodeCharacterData[index].CodePointRange.CompareCodePoint(codePoint);
if (Δ == 0) return unicodeCharacterData[index];
if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1;
} while (minIndex <= maxIndex);
return null;
return -1;
}
private static UnihanCharacterData FindUnihanCodePoint(int codePoint)
private static int FindUnihanCodePointIndex(int codePoint)
{
int minIndex;
int maxIndex;
if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint)
{
return null;
return -1;
}
do
@@ -333,12 +331,12 @@ namespace System.Unicode
int Δ = codePoint - unihanCharacterData[index].CodePoint;
if (Δ == 0) return unihanCharacterData[index];
if (Δ == 0) return index;
else if (Δ < 0) maxIndex = index - 1;
else minIndex = index + 1;
} while (minIndex <= maxIndex);
return null;
return -1;
}
private static int FindBlockIndex(int codePoint)
@@ -360,16 +358,26 @@ namespace System.Unicode
return -1;
}
internal static ref UnicodeCharacterData GetUnicodeCharacterData(int index)
{
if (index >= 0) return ref unicodeCharacterData[index];
return ref DefaultUnicodeCharacterData;
}
internal static ref UnihanCharacterData GetUnihanCharacterData(int index)
{
if (index >= 0) return ref unihanCharacterData[index];
return ref DefaultUnihanCharacterData;
}
/// <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 : DefaultBlock;
}
=> FindBlockIndex(codePoint) is int i && i >= 0 ?
blocks[i].Name :
DefaultBlock;
/// <summary>Gets Unicode information on the specified code point.</summary>
/// <remarks>
@@ -397,9 +405,7 @@ namespace System.Unicode
/// <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));
}
=> new UnicodeCharInfo(codePoint, FindUnicodeCodePointIndex(codePoint), FindUnihanCodePointIndex(codePoint), GetBlockName(codePoint));
/// <summary>Gets the category of the specified code point.</summary>
/// <remarks>
@@ -409,29 +415,35 @@ namespace System.Unicode
/// <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 charData = FindUnicodeCodePoint(codePoint);
return charData != null ? charData.Category : UnicodeCategory.OtherNotAssigned;
}
=> FindUnicodeCodePointIndex(codePoint) is int unicodeCharacterDataIndex && unicodeCharacterDataIndex >= 0 ?
GetUnicodeCharacterData(unicodeCharacterDataIndex).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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static string GetDisplayText(this UnicodeCharInfo charInfo)
=> GetDisplayText(charInfo.CodePoint, charInfo.unicodeCharacterDataIndex);
/// <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();
if (codePoint <= 0x0020) return ((char)(0x2400 + codePoint)).ToString(); // Provide a display text for control characters, including space.
else if (GetCategory(codePoint) == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(codePoint);
else if (codePoint >= 0xD800 && codePoint <= 0xDFFF) return "\xFFFD";
else if (codePoint >= 0xE0020 && codePoint < 0xE007F) return char.ConvertFromUtf32(codePoint - 0xE0000); // Handle "TAG" ASCII subset by remapping it to regular ASCII
else return char.ConvertFromUtf32(codePoint);
}
private static string GetDisplayText(int codePoint, int unicodeCharacterDataIndex)
{
if (codePoint <= 0x0020) return ((char)(0x2400 + codePoint)).ToString(); // Provide a display text for control characters, including space.
else if (GetUnicodeCharacterData(unicodeCharacterDataIndex).Category == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(codePoint);
else if (codePoint >= 0xD800 && codePoint <= 0xDFFF) return "\xFFFD";
else if (codePoint >= 0xE0020 && codePoint < 0xE007F) return char.ConvertFromUtf32(codePoint - 0xE0000); // Handle "TAG" ASCII subset by remapping it to regular ASCII
else return char.ConvertFromUtf32(codePoint);
}
@@ -443,12 +455,16 @@ namespace System.Unicode
/// <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));
}
=> HangulInfo.IsHangul(codePoint) ?
HangulInfo.GetHangulName((char)codePoint) :
GetNameInternal(codePoint);
internal static string GetName(int codePoint, UnicodeCharacterData characterData)
private static string GetNameInternal(int codePoint)
=> FindUnicodeCodePointIndex(codePoint) is int codePointInfoIndex && codePointInfoIndex >= 0 ?
GetName(codePoint, ref GetUnicodeCharacterData(codePointInfoIndex)) :
null;
internal static string GetName(int codePoint, ref UnicodeCharacterData characterData)
{
if (characterData.CodePointRange.IsSingleCodePoint) return characterData.Name;
else if (HangulInfo.IsHangul(codePoint)) return HangulInfo.GetHangulName((char)codePoint);
@@ -461,20 +477,15 @@ namespace System.Unicode
/// <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]);
}
=> 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; } }
public static int CjkRadicalCount => 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();
}
public static UnicodeBlock[] GetBlocks() => (UnicodeBlock[])blocks.Clone();
}
}
+39 -96
View File
@@ -1,110 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<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')" />
<Project Sdk="Microsoft.Net.Sdk">
<Import Project="../Common.props" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{CB722958-A1C4-4121-804B-7D5A671491B1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace>System.Unicode</RootNamespace>
<AssemblyName>UnicodeInformation</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<_WindowsKitBinPath>C:\Program Files (x86)\Windows Kits\8.1\bin\x86</_WindowsKitBinPath>
<_WindowsPhoneKitBinPath>C:\Program Files (x86)\Windows Phone Kits\8.1\bin</_WindowsPhoneKitBinPath>
<MakePriExeFullPath>$(_WindowsKitBinPath)\makepri.exe</MakePriExeFullPath>
<MakeAppxExeFullPath>$(_WindowsKitBinPath)\makeappx.exe</MakeAppxExeFullPath>
<SignAppxPackageExeFullPath>$(_WindowsKitBinPath)\signtool.exe</SignAppxPackageExeFullPath>
<MakePriExtensionPath>$(_WindowsPhoneKitBinPath)\x86\MrmEnvironmentExtDl.dll</MakePriExtensionPath>
<MakePriExtensionPath_x64>$(_WindowsPhoneKitBinPath)\x64\MrmEnvironmentExtDl.dll</MakePriExtensionPath_x64>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DocumentationFile>
</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>..\System.Unicode.snk</AssemblyOriginatorKeyFile>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup Label="Package">
<PackageId>UnicodeInfo</PackageId>
<Title>Unicode Information Library</Title>
<AssemblyTitle>Unicode Information Library</AssemblyTitle>
<Description>Library providing access to Unicode data to .NET clients.</Description>
<PackageTags>Unicode Unihan Data .NET C# String Text Char Character CodePoint Code Point</PackageTags>
<PackageLicenseUrl>http://opensource.org/licenses/MIT</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/ceee/NetUnicodeInfo/</PackageProjectUrl>
<PackageIconUrl>https://raw.githubusercontent.com/ceee/NetUnicodeInfo/master/UnicodeCharacterInspector/UnicodeCharacterInspector.ico</PackageIconUrl>
<PackageReleaseNotes>Version 2.3.0
-------------
Converted to .NET Standard 2.0 project.
Version 2.2.1
-------------
Added DebuggerDisplay attributes on various types.
Version 2.2.0
-------------
Added emoji properties.
Version 2.1.0
-------------
Support for Unicode 10.0.
Version 2.0.0
-------------
Following migration to Unicode 9.0.0, UnicodeRadicalStrokeCount.StrokeCount is now of type System.SByte instead of type System.Byte.</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<None Include="..\System.Unicode.snk">
<Link>System.Unicode.snk</Link>
</None>
<None Include="app.config" />
<None Remove="ucd.dat" />
<EmbeddedResource Include="ucd.dat">
<LogicalName>ucd.dat</LogicalName>
</EmbeddedResource>
<None Include="..\System.Unicode.snk">
<Link>System.Unicode.snk</Link>
</None>
</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" />
<Compile Include="StringExtensions.cs" />
<Compile Include="UnicodeBlock.cs" />
<Compile Include="UnicodeCategoryExtensions.cs" />
<Compile Include="UnicodeCategoryInfo.cs" />
<Compile Include="UnicodeCharacterData.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" />
<Compile Include="UnihanFields.cs" />
<Compile Include="ValueNameAttribute.cs" />
<Compile Include="UnicodeRationalNumber.cs" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.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.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
@@ -1,18 +0,0 @@
<?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>
+12 -1
View File
@@ -1,12 +1,23 @@
namespace System.Unicode
using System.Diagnostics;
using System.Linq;
namespace System.Unicode
{
/// <summary>Represents a name alias for an Unicode code point.</summary>
[DebuggerDisplay("{DisplayText,nq}")]
public struct UnicodeNameAlias
{
internal static readonly UnicodeNameAlias[] EmptyArray = new UnicodeNameAlias[0];
/// <summary>Gets the alias name.</summary>
/// <value>The name.</value>
public string Name { get; }
/// <summary>Gets the kind of alias.</summary>
/// <value>The kind of alias.</value>
public UnicodeNameAliasKind Kind { get; }
private string DisplayText => (Kind != 0 ? "<" + EnumHelper<UnicodeNameAliasKind>.GetValueNames(Kind).FirstOrDefault() + "> " : string.Empty) + Name;
internal UnicodeNameAlias(string name, UnicodeNameAliasKind kind)
{
Name = name;
@@ -1,40 +1,51 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Represents a collection of name aliases.</summary>
public struct UnicodeNameAliasCollection : IList<UnicodeNameAlias>
{
/// <summary>Represents an enumerator for the <see cref="UnicodeNameAliasCollection"/> class.</summary>
public struct Enumerator : IEnumerator<UnicodeNameAlias>
{
private readonly UnicodeNameAlias[] items;
private int index;
/// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct.</summary>
/// <param name="items">The items to enumerate.</param>
internal Enumerator(UnicodeNameAlias[] items)
{
this.items = items;
this.index = -1;
}
/// <summary>Does nothing.</summary>
public void Dispose() { }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public UnicodeNameAlias Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
/// <summary>Gets an empty <see cref="UnicodeNameAliasCollection"/> struct.</summary>
public static readonly UnicodeNameAliasCollection Empty = new UnicodeNameAliasCollection(UnicodeNameAlias.EmptyArray);
private readonly UnicodeNameAlias[] items;
public UnicodeNameAliasCollection() { items = UnicodeNameAlias.EmptyArray; }
internal UnicodeNameAliasCollection(UnicodeNameAlias[] items) { this.items = items ?? UnicodeNameAlias.EmptyArray; }
/// <summary>Gets the <see cref="UnicodeNameAlias"/> at the specified index.</summary>
/// <value>The <see cref="UnicodeNameAlias"/>.</value>
/// <param name="index">The index.</param>
/// <returns>The <see cref="UnicodeNameAlias"/> at the specified index.</returns>
public UnicodeNameAlias this[int index] { get { return items[index]; } }
UnicodeNameAlias IList<UnicodeNameAlias>.this[int index]
@@ -43,23 +54,38 @@ namespace System.Unicode
set { throw new NotSupportedException(); }
}
/// <summary>Gets the number of elements contained in the <see cref="UnicodeNameAliasCollection"/>.</summary>
/// <value>The number of elements contained in the <see cref="UnicodeNameAliasCollection"/>.</value>
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(); }
void ICollection<UnicodeNameAlias>.Add(UnicodeNameAlias item) { throw new NotSupportedException(); }
void IList<UnicodeNameAlias>.Insert(int index, UnicodeNameAlias item) { throw new NotSupportedException(); }
public bool Remove(UnicodeNameAlias item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
bool ICollection<UnicodeNameAlias>.Remove(UnicodeNameAlias item) { throw new NotSupportedException(); }
void IList<UnicodeNameAlias>.RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
void ICollection<UnicodeNameAlias>.Clear() { throw new NotSupportedException(); }
/// <summary>Determines the index of a specific item in the <see cref="UnicodeNameAliasCollection"/>.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeNameAliasCollection"/>.</param>
/// <returns>The index of the item if found in the list; otherwise, -1.</returns>
public int IndexOf(UnicodeNameAlias item) { return Array.IndexOf(items, item); }
/// <summary>Determines whether the <see cref="UnicodeNameAliasCollection"/> contains a specific value.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeNameAliasCollection"/>.</param>
/// <returns><see langword="true" /> if item is fount in the <see cref="UnicodeNameAliasCollection"/>; <see langword="false" /> otherwise.</returns>
public bool Contains(UnicodeNameAlias item) { return IndexOf(item) >= 0; }
/// <summary>
/// Copies the elements of the UnicodeNameAliasCollection to an <see cref="System.Array" />, starting at a particular <see cref="System.Array" /> index.
/// </summary>
/// <param name="array">The one-dimensional <see cref="System.Array" /> that is the destination of the elements to copy from UnicodeNameAliasCollection. The <see cref="System.Array" /> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zeo-based index in array at which copy begins.</param>
public void CopyTo(UnicodeNameAlias[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
/// <summary>Returns an enumerator that iterates through the collection.</summary>
/// <returns>An <see cref="Enumerator"/> that can be used to iterate through the collection.</returns>
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<UnicodeNameAlias> IEnumerable<UnicodeNameAlias>.GetEnumerator() { return GetEnumerator(); }
@@ -1,15 +1,21 @@
namespace System.Unicode
{
/// <summary>Provides information on the kind of name alias provided for a code point.</summary>
public enum UnicodeNameAliasKind : byte
{
/// <summary>The alias is a correction of a serious problem in the original name.</summary>
[ValueName("correction")]
Correction = 1,
/// <summary>The alias provides the ISO 6429 name for C0 and C1 control functions of a control code, or another commonly occurring name for the control code.</summary>
[ValueName("control")]
Control = 2,
/// <summary>The alias is a widely used alternate name for a format character.</summary>
[ValueName("alternate")]
Alternate = 3,
/// <summary>The alias is a documented non-standardized label for C1 control code points.</summary>
[ValueName("figment")]
Figment = 4,
/// <summary>The alias is a commonly occurring abbreviation (or acronym) for control codes, format characters, spaces, and variation selectors.</summary>
[ValueName("abbreviation")]
Abbreviation = 5
}
+6 -7
View File
@@ -1,16 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Represents the value of the Numeric_Type property.</summary>
public enum UnicodeNumericType : byte
{
/// <summary>The code point has no numeric value.</summary>
None = 0,
/// <summary>The code point represents a decimal digit which is part of a contiguous ascending range of characters from 0 to 9, and can be used in a decimal radix positional numeral system.</summary>
Decimal = 1,
/// <summary>The code point represents a digit between 0 and 9 and requires special handling.</summary>
Digit = 2,
/// <summary>The code point represents another kind of numeric value.</summary>
Numeric = 3
}
}
+36 -18
View File
@@ -1,33 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
namespace System.Unicode
{
/// <summary>Provides information on radical and additional stroke count for a code point.</summary>
/// <remarks>Values of this type are usually associated with the property kRSUnicode (aka. Unicode_Radical_Stroke).</remarks>
[DebuggerDisplay(@"{IsSimplified ? ""Simplified"" : ""Traditional"",nq} Radical {Radical} + {StrokeCount} Strokes")]
public struct UnicodeRadicalStrokeCount
{
internal static readonly UnicodeRadicalStrokeCount[] EmptyArray = new UnicodeRadicalStrokeCount[0];
private readonly byte radical;
private readonly byte strokeCount;
/// <summary>Initializes a new instance of the class <see cref="UnicodeRadicalStrokeCount"/> from raw data.</summary>
/// <param name="rawRadical">The raw value to use for <see cref="Radical"/>.</param>
/// <param name="rawStrokeCount">The raw value to use for <see cref="RawStrokeCount"/>.</param>
internal UnicodeRadicalStrokeCount(byte rawRadical, byte rawStrokeCount)
{
radical = rawRadical;
strokeCount = rawStrokeCount;
Radical = rawRadical;
RawStrokeCount = rawStrokeCount;
}
internal UnicodeRadicalStrokeCount(byte radical, byte strokeCount, bool isSimplified)
/// <summary>Initializes a new instance of the class <see cref="UnicodeRadicalStrokeCount"/>.</summary>
/// <remarks><paramref name="strokeCount"/> must be between -64 and 63 included.</remarks>
/// <param name="radical">The index of the Kangxi radical of the character.</param>
/// <param name="strokeCount">The number of additional strokes required to form the character from the radical.</param>
/// <param name="isSimplified">Indicates whether the character is simplified.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="strokeCount"/> is outside of the allowed range.</exception>
internal UnicodeRadicalStrokeCount(byte radical, sbyte strokeCount, bool isSimplified)
{
this.radical = radical;
if (isSimplified) strokeCount |= 0x80;
this.strokeCount = strokeCount;
if (strokeCount < -64 || strokeCount > 63) throw new ArgumentOutOfRangeException(nameof(strokeCount));
Radical = radical;
// Pack strokeCount together with isSimplified in a single byte.
RawStrokeCount = unchecked((byte)(strokeCount & 0x7F | (isSimplified ? 0x80 : 0x00)));
}
public byte Radical { get { return radical; } }
public byte StrokeCount { get { return (byte)(strokeCount & 0x7F); } }
public bool IsSimplified { get { return (strokeCount & 0x80) != 0; } }
}
/// <summary>Gets the index of the Kangxi radical of the character.</summary>
/// <remarks>The Kangxi radicals are numbered from 1 to 214 inclusive.</remarks>
/// <value>The index of the Kangxi radical.</value>
public byte Radical { get; }
/// <summary>Gets the value of <see cref="StrokeCount"/> packed with <see cref="IsSimplified"/>.</summary>
/// <remarks>The stroke count is stored as a 7bit signed value, together with the <see cref="IsSimplified"/> flag as a 1bit value.</remarks>
/// <value>The raw value of <see cref="StrokeCount"/>.</value>
internal byte RawStrokeCount { get; }
/// <summary>Gets the additional stroke count.</summary>
/// <value>The additional stroke count.</value>
public sbyte StrokeCount { get { return unchecked((sbyte)(RawStrokeCount & 0x7F | (RawStrokeCount & 0x40) << 1)); } } // To unpack the stroke count, we simply need to copy bit 6 to bit 7.
/// <summary>Gets a value indicating whether the information is based on the simplified form of the radical.</summary>
/// <value><see langword="true" /> if the information is based on the simplified form of the radical; otherwise, <see langword="false" />.</value>
public bool IsSimplified { get { return (RawStrokeCount & 0x80) != 0; } }
}
}
@@ -1,40 +1,51 @@
using System;
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
{
/// <summary>Represents a collection of values for the kRSUnicode (aka. Unicode_Radical_Stroke) property.</summary>
public struct UnicodeRadicalStrokeCountCollection : IList<UnicodeRadicalStrokeCount>
{
/// <summary>Represents an enumerator for the <see cref="UnicodeRadicalStrokeCountCollection"/> class.</summary>
public struct Enumerator : IEnumerator<UnicodeRadicalStrokeCount>
{
private readonly UnicodeRadicalStrokeCount[] items;
private int index;
/// <summary>Initializes a new instance of the <see cref="Enumerator"/> struct.</summary>
/// <param name="items">The items to enumerate.</param>
internal Enumerator(UnicodeRadicalStrokeCount[] items)
{
this.items = items;
this.index = -1;
}
/// <summary>Does nothing.</summary>
public void Dispose() { }
/// <summary>Gets the element in the collection at the current position of the enumerator..</summary>
/// <value>The element in the collection at the current position of the enumerator.</value>
public UnicodeRadicalStrokeCount Current { get { return items[index]; } }
object IEnumerator.Current { get { return Current; } }
/// <summary>Advances the enumerator to the next element of the collection.</summary>
/// <returns>true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.</returns>
public bool MoveNext() { return index < items.Length && ++index < items.Length; }
void IEnumerator.Reset() { this.index = -1; }
}
/// <summary>Gets an empty <see cref="UnicodeRadicalStrokeCountCollection"/> struct.</summary>
public static readonly UnicodeRadicalStrokeCountCollection Empty = new UnicodeRadicalStrokeCountCollection(null);
private readonly UnicodeRadicalStrokeCount[] items;
public UnicodeRadicalStrokeCountCollection() { items = UnicodeRadicalStrokeCount.EmptyArray; }
internal UnicodeRadicalStrokeCountCollection(UnicodeRadicalStrokeCount[] items) { this.items = items ?? UnicodeRadicalStrokeCount.EmptyArray; }
/// <summary>Gets the <see cref="UnicodeRadicalStrokeCount"/> at the specified index.</summary>
/// <value>The <see cref="UnicodeRadicalStrokeCount"/>.</value>
/// <param name="index">The index.</param>
/// <returns>The <see cref="UnicodeRadicalStrokeCount"/> at the specified index.</returns>
public UnicodeRadicalStrokeCount this[int index] { get { return items[index]; } }
UnicodeRadicalStrokeCount IList<UnicodeRadicalStrokeCount>.this[int index]
@@ -43,23 +54,41 @@ namespace System.Unicode
set { throw new NotSupportedException(); }
}
/// <summary>Gets the number of elements contained in the <see cref="UnicodeRadicalStrokeCountCollection"/>.</summary>
/// <value>The number of elements contained in the <see cref="UnicodeRadicalStrokeCountCollection"/>.</value>
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(); }
void ICollection<UnicodeRadicalStrokeCount>.Add(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
void IList<UnicodeRadicalStrokeCount>.Insert(int index, UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
public bool Remove(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
public void RemoveAt(int index) { throw new NotSupportedException(); }
bool ICollection<UnicodeRadicalStrokeCount>.Remove(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
void IList<UnicodeRadicalStrokeCount>.RemoveAt(int index) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
void ICollection<UnicodeRadicalStrokeCount>.Clear() { throw new NotSupportedException(); }
/// <summary>Determines the index of a specific item in the <see cref="UnicodeRadicalStrokeCountCollection"/>.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeRadicalStrokeCountCollection"/>.</param>
/// <returns>The index of the item if found in the list; otherwise, -1.</returns>
public int IndexOf(UnicodeRadicalStrokeCount item) { return Array.IndexOf(items, item); }
/// <summary>Determines whether the <see cref="UnicodeRadicalStrokeCountCollection"/> contains a specific value.</summary>
/// <param name="item">The object to locate in the <see cref="UnicodeRadicalStrokeCountCollection"/>.</param>
/// <returns><see langword="true" /> if item is fount in the <see cref="UnicodeRadicalStrokeCountCollection"/>; <see langword="false" /> otherwise.</returns>
public bool Contains(UnicodeRadicalStrokeCount item) { return IndexOf(item) >= 0; }
/// <summary>Copies the elements of the UnicodeRadicalStrokeCountCollection to an <see cref="System.Array" />, starting at a particular <see cref="System.Array" /> index.</summary>
/// <param name="array">The one-dimensional <see cref="System.Array" /> that is the destination of the elements to copy from UnicodeRadicalStrokeCountCollection. The <see cref="System.Array" /> must have zero-based indexing.</param>
/// <param name="arrayIndex">The zeo-based index in array at which copy begins.</param>
public void CopyTo(UnicodeRadicalStrokeCount[] array, int arrayIndex) { items.CopyTo(array, arrayIndex); }
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="Enumerator"/> that can be used to iterate through the collection.
/// </returns>
public Enumerator GetEnumerator() { return new Enumerator(items); }
IEnumerator<UnicodeRadicalStrokeCount> IEnumerable<UnicodeRadicalStrokeCount>.GetEnumerator() { return GetEnumerator(); }
+30 -7
View File
@@ -1,13 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Represents a rational number in a format compatible with the Unicode standard.</summary>
public struct UnicodeRationalNumber : IEquatable<UnicodeRationalNumber>
{
/// <summary>Parses a rational number from a string representation.</summary>
/// <remarks>
/// Valid text representations should match the regex pattern /-?[0-9]+(?:\/[0-9]+)/.
/// The numerator part should fit in a <see cref="long"/>, and the denominator part should fit in a <see cref="byte"/>.
/// </remarks>
/// <param name="s">The string to parse.</param>
/// <returns>The rational number parsed from the string.</returns>
/// <exception cref="ArgumentNullException">The parameter <paramref name="s"/> is <see langword="null"/>.</exception>
/// <exception cref="ArgumentException">The parameter <paramref name="s"/> is empty.</exception>
public static UnicodeRationalNumber Parse(string s)
{
if (s == null) throw new ArgumentNullException(nameof(s));
@@ -18,39 +22,58 @@ namespace System.Unicode
return new UnicodeRationalNumber(long.Parse(fractionBarIndex >= 0 ? s.Substring(0, fractionBarIndex) : s), fractionBarIndex >= 0 ? byte.Parse(s.Substring(fractionBarIndex + 1)) : (byte)1);
}
/// <summary>The numerator of the fraction.</summary>
public readonly long Numerator;
/// <summary>The denominator of the fraction.</summary>
public readonly byte Denominator;
/// <summary>Initializes a new instance of the <see cref="UnicodeRationalNumber"/> structure that represents a signed integer..</summary>
/// <param name="number">The number which should be represented as a rational number.</param>
public UnicodeRationalNumber(long number)
{
this.Numerator = number;
this.Denominator = 1;
}
/// <summary>Initializes a new instance of the <see cref="UnicodeRationalNumber"/> structure that represents a signed integer..</summary>
/// <param name="numerator">The number which should be used as numerator in the rational number.</param>
/// <param name="denominator">The number which should be used as denominator in the rational number.</param>
public UnicodeRationalNumber(long numerator, byte denominator)
{
this.Numerator = numerator;
this.Denominator = denominator;
}
/// <summary>Gets a value indicating whether the current value is the default value of the type.</summary>
/// <remarks>The default value is an invalid fraction of 0/0.</remarks>
public bool IsDefaultValue { get { return Numerator == 0 && Denominator == 0; } }
/// <summary>Creates a string representation of the current rational number.</summary>
/// <returns>The created representation is culture invariant, and will be parsable by the <see cref="Parse(string)"/> method.</returns>
public override string ToString()
{
return !IsDefaultValue ? Denominator != 1 ? Numerator.ToString() + "/" + Denominator.ToString() : Numerator.ToString() : string.Empty;
}
/// <summary>Determines whether the specified rational number is equal to the current value.</summary>
/// <param name="other">The other value to compare to the current one.</param>
/// <returns><see langword="true"/> if the two values are the same; <see langword="false"/> otherwise.</returns>
public bool Equals(UnicodeRationalNumber other)
{
// We don't consider 1/2 and 2/4 equal here, as, that wouldn't be the same character.
return other.Numerator == Numerator && other.Denominator == Denominator;
}
/// <summary>Determines whether the specified object is equal to the current rational number.</summary>
/// <param name="obj">The object to compare to the current rational number.</param>
/// <returns><see langword="true"/> if the object represents the same rational number; <see langword="false"/> otherwise.</returns>
public override bool Equals(object obj)
{
return base.Equals(obj);
}
/// <summary>Returns the hash code for the current rational number.</summary>
/// <returns>A 32-bit signed integer hash code.</returns>
public override int GetHashCode()
{
return (int)(Numerator << 8) | (Denominator) ^ (byte)(Numerator >> 56);
+2 -8
View File
@@ -1,12 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
internal sealed class UnihanCharacterData
internal struct UnihanCharacterData
{
public readonly int CodePoint;
public readonly UnihanNumericType NumericType;
+1 -7
View File
@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
[Flags]
internal enum UnihanFields : ushort
+8 -7
View File
@@ -1,19 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Represents the different numeric types from the Unihan database.</summary>
public enum UnihanNumericType : byte
{
/// <summary>Indicates that there is no Unihan numeric property defined for the code point.</summary>
None = 0,
/// <summary>Indicates that the propery kPrimaryNumeric is defined for this code point.</summary>
/// <remarks>The kPrimaryNumeric property is used for ideographs wich are standard numerals.</remarks>
[ValueName("kPrimaryNumeric")]
Primary = 1,
/// <summary>Indicates that the propery kAccountingNumeric is defined for this code point.</summary>
/// <remarks>The kAccountingNumeric property is used for ideographs used as accounting numerals.</remarks>
[ValueName("kAccountingNumeric")]
Accounting = 2,
/// <summary>Indicates that the propery kOtherNumeric is defined for this code point.</summary>
/// <remarks>The kOtherNumeric property is used for ideographs wich are used as numerals in non common contexts.</remarks>
[ValueName("kOtherNumeric")]
Other = 3,
}
+9 -7
View File
@@ -1,18 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System.Unicode
namespace System.Unicode
{
/// <summary>Declares a name for a specific value.</summary>
/// <remarks>
/// Since this project tries to stick to the .NET Framework naming conventions, this attribute may be used to indicate standard property names and values names where applicable.
/// It may also be of use when aliases are available for a given property or value.
/// </remarks>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
public sealed class ValueNameAttribute : Attribute
{
private readonly string name;
/// <summary>The name given to the property or value.</summary>
public string Name { get { return name; } }
/// <summary>Initializes an instance of the class <see cref="ValueNameAttribute"/>.</summary>
/// <param name="name">The name given to the property or value on which this attribute is to be applied.</param>
public ValueNameAttribute(string name)
{
this.name = name;
-15
View File
@@ -1,15 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.9.0" newVersion="2.6.9.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.6.9.0" newVersion="2.6.9.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Binary file not shown.
+36
View File
@@ -0,0 +1,36 @@
version: 2.3.0.{build}
image: Visual Studio 2017
configuration: Release
platform: Any CPU
assembly_info:
patch: true
file: AssemblyInfo.Common.*
assembly_version: '{version}'
assembly_file_version: '{version}'
assembly_informational_version: '{version}-CI'
dotnet_csproj:
patch: true
file: Common.props
version: '{version}'
package_version: '{version}'
before_build:
- cmd: nuget restore
build:
verbosity: minimal
test_script:
- cmd: >-
cd UnicodeInformation.Tests
dotnet xunit
artifacts:
- path: UnicodeCharacterInspector\bin\Release
name: UnicodeCharacterInspector
- path: UnicodeInformation\bin\Release\UnicodeInformation.*.nupkg
name: NuGet
deploy:
- provider: NuGet
api_key:
secure: S1uTeXbjD8eLun90hsjHjyf2TpjxOWS9YW7Z2Xu7Cg/sV5ogRm7OAr9P7E5lhueE
skip_symbols: true
on:
branch: master