Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6106f8e7ea | |||
| cac4c9de8b | |||
| 751e84fc6d | |||
| d65f7f0a77 | |||
| 642b675b3d | |||
| f9976c7a03 | |||
| b9d732f561 | |||
| 8238c532ec | |||
| 968130e59e | |||
| 04211241bc | |||
| bce0e6e20b | |||
| 91b1d3b2ef | |||
| 87e5c4a523 | |||
| ca267468e5 | |||
| 660fbd49f2 | |||
| e6ace93e19 | |||
| de6140734f | |||
| a997a88505 | |||
| c7230ad446 | |||
| 24909bf28d | |||
| 58e4cc8802 | |||
| 301d7b6e98 | |||
| a09eef8196 | |||
| 23823a6626 | |||
| 3cf36ec6de | |||
| ff47b6a9f1 | |||
| e3cada4ca7 | |||
| 07b4086423 | |||
| a429d83bdb | |||
| f0b7ccb607 | |||
| 04b03edee2 | |||
| 6b4e1da5bf | |||
| bc07cc9b55 | |||
| 63fd694c26 | |||
| 0012ef2434 | |||
| 4f5ac9d555 | |||
| da53411d30 | |||
| fd2e8122ed | |||
| 3abba328ee | |||
| 38a9d989ff | |||
| f8d468bc94 | |||
| 0d3239d700 | |||
| 84e1a40612 | |||
| 78baae7ff2 | |||
| 475e9c5e44 | |||
| 76e5b5f0ba | |||
| 2fd517a286 | |||
| 4f03ba85d9 | |||
| 95fd83cb6d | |||
| 21253a170e | |||
| ee8c1b1f6e | |||
| 2324d2c272 | |||
| b148e69ca0 | |||
| d5131ef008 | |||
| 343dc823cf | |||
| 4119824ffc | |||
| 83fb677dc2 | |||
| c895b2e627 | |||
| 694a749046 | |||
| 5c47c98b18 | |||
| 3893b22fc0 | |||
| ea1a498aff | |||
| 11f2619411 | |||
| 9c3cd4207b |
+2
-1
@@ -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
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if DEBUG
|
||||
[assembly: AssemblyConfiguration("Debug")]
|
||||
#else
|
||||
[assembly: AssemblyConfiguration("Release")]
|
||||
#endif
|
||||
[assembly: AssemblyCompany("Fabien Barbier")]
|
||||
[assembly: AssemblyProduct(".NET Unicode Information")]
|
||||
[assembly: AssemblyCopyright("Copyright © Fabien Barbier 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: AssemblyVersion("2.2.0.0")]
|
||||
[assembly: AssemblyFileVersion("2.2.0.0")]
|
||||
@@ -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>
|
||||
@@ -1,15 +1,34 @@
|
||||
.NET Unicode Information Library
|
||||
========================
|
||||
Unicode Character Inspector & .NET Unicode Information Library
|
||||
==============================================================
|
||||
|
||||
[](https://ci.appveyor.com/project/GoldenCrystal/netunicodeinfo/branch/master)
|
||||
|
||||
Summary
|
||||
-------
|
||||
This projects provides access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
|
||||
Included, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
|
||||
This projects has two parts.
|
||||
One is a library, providing access to some of the data contained in the Unicode Character Database by the means of a portable .NET assembly.
|
||||
The other, is a small WPF application allowing to inspect the Unicode code points composing a specified text.
|
||||
|
||||
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.
|
||||

|
||||
|
||||
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
|
||||
Using the library is as easy as including it in your project. You will find all the good stuff in the System.Unicode namespace.
|
||||
Grab the latest version of the package on NuGet: https://www.nuget.org/packages/UnicodeInformation/.
|
||||
Once the library is installed in your project, you will find everything you need in the System.Unicode namespace.
|
||||
|
||||
Let's see a simple example:
|
||||
|
||||
@@ -46,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
|
||||
@@ -56,13 +75,14 @@ This library includes a subset of the official [Unicode Character Database](http
|
||||
* Bidi_Class
|
||||
* Decomposition_Type
|
||||
* Decomposition_Mapping
|
||||
* Numeric_Type (*)
|
||||
* Numeric_Type (See also kAccountingNumeric/kOtherNumeric/kPrimaryNumeric. Those will set Numeric_Type to Numeric.)
|
||||
* Numeric_Value
|
||||
* Bidi_Mirrored
|
||||
* Unicode_1_Name
|
||||
* Simple_Uppercase_Maping
|
||||
* Simple_Lowercase_Mapping
|
||||
* Simple_Titlecase_Mapping
|
||||
* Name_Alias
|
||||
* Block
|
||||
* ASCII_Hex_Digit
|
||||
* Bidi_Control
|
||||
@@ -115,6 +135,8 @@ This library includes a subset of the official [Unicode Character Database](http
|
||||
* ID_Continue
|
||||
* XID_Start
|
||||
* XID_Continue
|
||||
* Unicode_Radical_Stroke (This is actually kRSUnicode from the Unihan database)
|
||||
* Code point cross references extracted from NamesList.txt
|
||||
|
||||
NB: The UCD property ISO_Comment will never be included since this one is empty in all new Unicode versions.
|
||||
|
||||
@@ -122,6 +144,7 @@ NB: The UCD property ISO_Comment will never be included since this one is empty
|
||||
* kAccountingNumeric
|
||||
* kOtherNumeric
|
||||
* kPrimaryNumeric
|
||||
* kRSUnicode
|
||||
* kDefinition
|
||||
* kMandarin
|
||||
* kCantonese
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,5 +7,10 @@
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
|
||||
<local:Utf32ToDisplayTextConverter x:Key="Utf32ToDisplayTextConverter" />
|
||||
<local:Utf32ToNameConverter x:Key="Utf32ToNameConverter" />
|
||||
<local:StringToUtf32Converter x:Key="StringToUtf32Converter" />
|
||||
<local:RadicalStrokeCountToCharConverter x:Key="RadicalStrokeCountToCharConverter" />
|
||||
<local:CodePointToFontFamilyConverter x:Key="CodePointToFontFamilyConverter" DefaultFontFamily="Segoe UI" EmojiFontFamily="Segoe UI Emoji" />
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
@@ -38,7 +35,7 @@ namespace UnicodeCharacterInspector
|
||||
storage = value;
|
||||
NotifyPropertyChanged(propertyName);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -47,12 +43,13 @@ namespace UnicodeCharacterInspector
|
||||
{
|
||||
codePoint = 0;
|
||||
characterInfo = UnicodeInfo.GetCharInfo(0);
|
||||
}
|
||||
}
|
||||
|
||||
NotifyPropertyChanged();
|
||||
UpdateDisplayText();
|
||||
NotifyPropertyChanged(nameof(CodePoint));
|
||||
NotifyPropertyChanged(nameof(Name));
|
||||
NotifyPropertyChanged(nameof(NameAliases));
|
||||
NotifyPropertyChanged(nameof(OldName));
|
||||
NotifyPropertyChanged(nameof(Definition));
|
||||
NotifyPropertyChanged(nameof(Category));
|
||||
@@ -66,6 +63,9 @@ namespace UnicodeCharacterInspector
|
||||
NotifyPropertyChanged(nameof(NumericValue));
|
||||
NotifyPropertyChanged(nameof(ContributoryProperties));
|
||||
NotifyPropertyChanged(nameof(CoreProperties));
|
||||
NotifyPropertyChanged(nameof(EmojiProperties));
|
||||
NotifyPropertyChanged(nameof(RadicalStrokeCounts));
|
||||
NotifyPropertyChanged(nameof(CrossReferences));
|
||||
NotifyPropertyChanged(nameof(MandarinReading));
|
||||
NotifyPropertyChanged(nameof(CantoneseReading));
|
||||
NotifyPropertyChanged(nameof(JapaneseKunReading));
|
||||
@@ -85,130 +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 string OldName
|
||||
{
|
||||
get { return character != null ? characterInfo.OldName : null; }
|
||||
}
|
||||
public string Definition => character != null ? characterInfo.Definition : null;
|
||||
|
||||
public string Definition
|
||||
{
|
||||
get { return character != null ? characterInfo.Definition : null; }
|
||||
}
|
||||
public UnicodeCategory? Category => character != null ? characterInfo.Category : null as UnicodeCategory?;
|
||||
public string Block => character != null ? characterInfo.Block : null;
|
||||
|
||||
public UnicodeCategory? Category
|
||||
{
|
||||
get { return character != null ? characterInfo.Category : null as UnicodeCategory?; }
|
||||
}
|
||||
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 string Block
|
||||
{
|
||||
get { return character != null ? characterInfo.Block : null; }
|
||||
}
|
||||
public string DecompositionMapping => character != null ? characterInfo.DecompositionMapping : null;
|
||||
|
||||
public CanonicalCombiningClass? CanonicalCombiningClass
|
||||
{
|
||||
get { return character != null ? characterInfo.CanonicalCombiningClass : null as CanonicalCombiningClass?; }
|
||||
}
|
||||
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 BidirectionalClass? BidirectionalClass
|
||||
{
|
||||
get { return character != null ? characterInfo.BidirectionalClass : null as BidirectionalClass?; }
|
||||
}
|
||||
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 CompatibilityFormattingTag? DecompositionType
|
||||
{
|
||||
get { return character != null && characterInfo.DecompositionMapping != null ? characterInfo.DecompositionType : null as CompatibilityFormattingTag?; }
|
||||
}
|
||||
public UnicodeRadicalStrokeCountCollection RadicalStrokeCounts => character != null ? characterInfo.UnicodeRadicalStrokeCounts : UnicodeRadicalStrokeCountCollection.Empty;
|
||||
|
||||
public string DecompositionMapping
|
||||
{
|
||||
get { return character != null ? characterInfo.DecompositionMapping : null; }
|
||||
}
|
||||
public UnicodeCrossReferenceCollection CrossReferences => character != null ? characterInfo.CrossRerefences : UnicodeCrossReferenceCollection.Empty;
|
||||
|
||||
public UnicodeNumericType? NumericType
|
||||
{
|
||||
get { return character != null ? characterInfo.NumericType : null as UnicodeNumericType?; }
|
||||
}
|
||||
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 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Unicode;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
@@ -23,7 +19,7 @@ namespace UnicodeCharacterInspector
|
||||
CodePoint = codePoint;
|
||||
Character = char.ConvertFromUtf32(codePoint);
|
||||
DisplayText = UnicodeInfo.GetDisplayText(codePoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class CharacterCollection : INotifyCollectionChanged, IList<CharacterViewModel>
|
||||
@@ -74,8 +70,8 @@ namespace UnicodeCharacterInspector
|
||||
|
||||
public void CopyTo(CharacterViewModel[] array, int arrayIndex)
|
||||
{
|
||||
if (array == null) throw new ArgumentNullException("array");
|
||||
if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex");
|
||||
if (array == null) throw new ArgumentNullException(nameof(array));
|
||||
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
||||
if (array.Length < arrayIndex + owner.codePoints.Length) throw new ArgumentException();
|
||||
|
||||
for (int i = 0, j = arrayIndex; i < owner.codePoints.Length; ++i, ++j)
|
||||
@@ -108,7 +104,7 @@ namespace UnicodeCharacterInspector
|
||||
public CharacterInspectorViewModel()
|
||||
{
|
||||
characterCollection = new CharacterCollection(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void NotifyCollectionChanged(NotifyCollectionChangedAction action)
|
||||
{
|
||||
@@ -143,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);
|
||||
|
||||
@@ -164,7 +160,7 @@ namespace UnicodeCharacterInspector
|
||||
NotifyPropertyChanged(nameof(SelectedCharacter));
|
||||
selectedCharacterInfo.Character = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<CharacterViewModel> Characters { get { return characterCollection; } }
|
||||
@@ -175,7 +171,7 @@ namespace UnicodeCharacterInspector
|
||||
set
|
||||
{
|
||||
if (selectedCharacterIndex < -1 || selectedCharacterIndex >= codePoints.Length)
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
if (value != selectedCharacterIndex)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
<Window.DataContext>
|
||||
<local:CharacterInspectorViewModel />
|
||||
</Window.DataContext>
|
||||
<Grid Margin="10">
|
||||
<Grid Margin="10">
|
||||
<Grid.Resources>
|
||||
<Style TargetType="{x:Type Label}" BasedOn="{StaticResource ResourceKey={x:Type Label}}">
|
||||
<Setter Property="Margin" Value="3" />
|
||||
@@ -37,15 +37,15 @@
|
||||
<ColumnDefinition Width="120" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsReturn="True" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ListBox Grid.Row="1" Grid.RowSpan="3" ItemsSource="{Binding Characters}" SelectedIndex="{Binding SelectedCharacterIndex}">
|
||||
<TextBox Grid.ColumnSpan="2" ScrollViewer.VerticalScrollBarVisibility="Auto" MinLines="1" MaxLines="5" AcceptsTab="True" AcceptsReturn="True" local:Placeholder.Text="Text to analyse" Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<ListBox Grid.Row="1" Grid.RowSpan="3" ItemsSource="{Binding Characters}" SelectedIndex="{Binding SelectedCharacterIndex}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<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.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>
|
||||
@@ -53,6 +53,9 @@
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="Margin" Value="6" />
|
||||
</Style>
|
||||
<Style TargetType="{x:Type ItemsControl}" BasedOn="{StaticResource ResourceKey={x:Type ItemsControl}}">
|
||||
<Setter Property="Margin" Value="6" />
|
||||
</Style>
|
||||
</Grid.Resources>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width ="Auto" />
|
||||
@@ -81,6 +84,10 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<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>
|
||||
@@ -90,47 +97,81 @@
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Name, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Name}" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="Old Name" />
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.OldName, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.OldName}" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.SimplifiedVariant}" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
|
||||
<TextBlock Grid.Row="4" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Contributory Properties" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="Core Properties" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Aliases" />
|
||||
<ItemsControl Grid.Row="3" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NameAliases.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.NameAliases}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="WrapWithOverflow">
|
||||
<Run Text="{Binding Name, Mode=OneTime}" /> (<Run Text="{Binding Kind, Mode=OneTime}" />)
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Radical & Stroke Count" />
|
||||
<ItemsControl Grid.Row="4" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.RadicalStrokeCounts.Count, Converter={StaticResource ZeroToVisibilityConverter}}" ItemsSource="{Binding SelectedCharacterInfo.RadicalStrokeCounts}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="WrapWithOverflow">
|
||||
Radical <Run Text="{Binding Radical, Mode=OneTime}" /> (<Run Text="{Binding Mode=OneTime, Converter={StaticResource RadicalStrokeCountToCharConverter}}" />), <Run Text="{Binding StrokeCount, Mode=OneTime}" /> strokes
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock Grid.Row="5" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Simplified Variant" />
|
||||
<TextBlock Grid.Row="5" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.SimplifiedVariant, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
“<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay}" />” U+<Run Text="{Binding SelectedCharacterInfo.SimplifiedVariant, Mode=OneWay, Converter={StaticResource StringToUtf32Converter}, StringFormat=X4}" />
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="6" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="Traditional Variant" />
|
||||
<TextBlock Grid.Row="6" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.TraditionalVariant, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.TraditionalVariant}" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="Unihan Definition" />
|
||||
<TextBlock Grid.Row="7" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.Definition, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Definition}" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Mandarin Reading" />
|
||||
<TextBlock Grid.Row="8" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.MandarinReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.MandarinReading}" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Cantonese Reading" />
|
||||
<TextBlock Grid.Row="9" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CantoneseReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CantoneseReading}" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese Kun Reading" />
|
||||
<TextBlock Grid.Row="10" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseKunReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseKunReading}" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Japanese On Reading" />
|
||||
<TextBlock Grid.Row="11" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.JapaneseOnReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.JapaneseOnReading}" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Korean Reading" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.KoreanReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.KoreanReading}" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="Hangul Reading" />
|
||||
<TextBlock Grid.Row="13" Grid.Column="1" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.HangulReading, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.HangulReading}" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="Category" />
|
||||
<TextBlock Grid.Row="14" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Category, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Category}" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="Block" />
|
||||
<TextBlock Grid.Row="15" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.Block, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.Block}" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Canonical Combining Class" />
|
||||
<TextBlock Grid.Row="16" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.CanonicalCombiningClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CanonicalCombiningClass}" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="Bidirectional Class" />
|
||||
<TextBlock Grid.Row="17" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.BidirectionalClass, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.BidirectionalClass}" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Type" />
|
||||
<TextBlock Grid.Row="18" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionType, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionType}" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="Decomposition Mapping" />
|
||||
<TextBlock Grid.Row="19" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.DecompositionMapping, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.DecompositionMapping}" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type" />
|
||||
<TextBlock Grid.Row="20" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericType}" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Numeric Type (Unihan)" />
|
||||
<TextBlock Grid.Row="21" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.UnihanNumericType, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.UnihanNumericType}" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="0" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="Numeric Value" />
|
||||
<TextBlock Grid.Row="22" Grid.Column="1" Visibility="{Binding SelectedCharacterInfo.NumericValue, Converter={StaticResource NullToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.NumericValue}" />
|
||||
<TextBlock Grid.Row="23" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Contributory Properties" />
|
||||
<TextBlock Grid.Row="23" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.ContributoryProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.ContributoryProperties}" />
|
||||
<TextBlock Grid.Row="24" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="Core Properties" />
|
||||
<TextBlock Grid.Row="24" Grid.Column="1" VerticalAlignment="Top" TextWrapping="WrapWithOverflow" Visibility="{Binding SelectedCharacterInfo.CoreProperties, Converter={StaticResource ZeroToVisibilityConverter}}" Text="{Binding SelectedCharacterInfo.CoreProperties}" />
|
||||
<TextBlock Grid.Row="25" Grid.Column="0" VerticalAlignment="Top" Visibility="{Binding SelectedCharacterInfo.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">
|
||||
“<Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToDisplayTextConverter}}" />” U+<Run Text="{Binding Mode=OneTime, StringFormat=X4}" /> <Run Text="{Binding Mode=OneTime, Converter={StaticResource Utf32ToNameConverter}}" />
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
// Inspired by http://stackoverflow.com/questions/833943/watermark-hint-text-placeholder-textbox-in-wpf
|
||||
internal static partial class Placeholder
|
||||
{
|
||||
public static string GetText(DependencyObject obj)
|
||||
{
|
||||
return (string)obj.GetValue(TextProperty);
|
||||
}
|
||||
|
||||
public static void SetText(DependencyObject obj, string value)
|
||||
{
|
||||
obj.SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached("Text", typeof(string), typeof(Placeholder), new PropertyMetadata(OnTextChanged));
|
||||
|
||||
private static readonly HashSet<Control> handledControls = new HashSet<Control>();
|
||||
|
||||
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = d as TextBoxBase;
|
||||
|
||||
if (d == null) return;
|
||||
|
||||
if (e.NewValue == null || "".Equals(e.NewValue)) UnregisterControl(control);
|
||||
else UpdateControl(control, (string)e.NewValue);
|
||||
}
|
||||
|
||||
private static void OnControlLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var control = (Control)sender;
|
||||
UpdateControl(control, GetText(control));
|
||||
}
|
||||
|
||||
private static void OnTextBoxGotKeyboardFocus(object sender, System.Windows.Input.KeyboardFocusChangedEventArgs e)
|
||||
{
|
||||
var control = (Control)sender;
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
|
||||
private static void UpdateControl(Control control, string placeholderText)
|
||||
{
|
||||
if (handledControls.Add(control))
|
||||
{
|
||||
RegisterControl(control);
|
||||
}
|
||||
|
||||
if (IsEmpty(control))
|
||||
{
|
||||
var adorner = GetAdorner(control) ?? AddAdorner(control);
|
||||
if (adorner != null) adorner.Text = placeholderText;
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void RegisterControl(Control control)
|
||||
{
|
||||
control.Loaded += OnControlLoaded;
|
||||
|
||||
var textBox = control as TextBoxBase;
|
||||
if (textBox != null) RegisterTextBox(textBox);
|
||||
}
|
||||
|
||||
private static void RegisterTextBox(TextBoxBase textBox)
|
||||
{
|
||||
textBox.GotKeyboardFocus += OnTextBoxGotKeyboardFocus;
|
||||
textBox.LostKeyboardFocus += OnControlLoaded;
|
||||
}
|
||||
|
||||
private static void UnregisterControl(Control control)
|
||||
{
|
||||
if (handledControls.Remove(control))
|
||||
{
|
||||
control.Loaded -= OnControlLoaded;
|
||||
|
||||
var textBox = control as TextBoxBase;
|
||||
if (textBox != null) UnregisterTextBox(textBox);
|
||||
|
||||
RemoveAdorner(control);
|
||||
}
|
||||
}
|
||||
|
||||
private static void UnregisterTextBox(TextBoxBase textBox)
|
||||
{
|
||||
textBox.GotKeyboardFocus -= OnTextBoxGotKeyboardFocus;
|
||||
textBox.LostKeyboardFocus -= OnControlLoaded;
|
||||
}
|
||||
|
||||
private static bool IsEmpty(Control control)
|
||||
{
|
||||
var textBox = control as TextBox;
|
||||
|
||||
if (textBox != null) return string.IsNullOrEmpty(textBox.Text);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static PlaceholderAdorner GetAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer != null)
|
||||
{
|
||||
var adorners = layer.GetAdorners(control);
|
||||
|
||||
if (adorners != null)
|
||||
{
|
||||
foreach (var adorner in adorners)
|
||||
{
|
||||
var placeholder = adorner as PlaceholderAdorner;
|
||||
|
||||
if (placeholder != null) return placeholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PlaceholderAdorner AddAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer == null) return null;
|
||||
|
||||
var placeholder = new PlaceholderAdorner(control);
|
||||
|
||||
layer.Add(placeholder);
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
private static void RemoveAdorner(Control control)
|
||||
{
|
||||
var layer = AdornerLayer.GetAdornerLayer(control);
|
||||
|
||||
if (layer == null) return;
|
||||
|
||||
var adorners = layer.GetAdorners(control);
|
||||
|
||||
if (adorners == null) return;
|
||||
|
||||
foreach (var adorner in adorners)
|
||||
{
|
||||
var placeholder = adorner as PlaceholderAdorner;
|
||||
|
||||
if (placeholder != null)
|
||||
{
|
||||
layer.Remove(placeholder);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal static partial class Placeholder
|
||||
{
|
||||
private sealed class PlaceholderAdorner : Adorner
|
||||
{
|
||||
public string Text { get; set; }
|
||||
|
||||
public PlaceholderAdorner(UIElement adornedElement)
|
||||
: base(adornedElement)
|
||||
{
|
||||
IsHitTestVisible = false;
|
||||
}
|
||||
|
||||
protected override Visual GetVisualChild(int index) { throw new InvalidOperationException(); }
|
||||
|
||||
protected override int VisualChildrenCount { get { return 0; } }
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
var control = ((Control)AdornedElement);
|
||||
|
||||
Rect adornedElementRect = new Rect(AdornedElement.RenderSize);
|
||||
drawingContext.DrawText
|
||||
(
|
||||
new FormattedText
|
||||
(
|
||||
Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface
|
||||
(
|
||||
control.FontFamily,
|
||||
control.FontStyle,
|
||||
control.FontWeight,
|
||||
control.FontStretch,
|
||||
SystemFonts.MessageFontFamily
|
||||
),
|
||||
control.FontSize,
|
||||
SystemColors.GrayTextBrush
|
||||
),
|
||||
// The offsets where experimentally determined on a Windows 8.1 machine. I'm willing to accept anything better. 😉
|
||||
new Point(control.BorderThickness.Left + control.Padding.Left + 5, control.BorderThickness.Top + control.Padding.Top + 3)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,11 @@
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeCharacterInspector")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeCharacterInspector")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
[assembly: AssemblyTitle("Unicode Character Inspector")]
|
||||
[assembly: AssemblyDescription("A character inspector for Unicode text.")]
|
||||
|
||||
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
@@ -39,17 +15,3 @@ using System.Windows;
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class RadicalStrokeCountToCharConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value == null) return null;
|
||||
|
||||
var radicalStrokeCount = (UnicodeRadicalStrokeCount)value;
|
||||
var radical = UnicodeInfo.GetCjkRadicalInfo(radicalStrokeCount.Radical);
|
||||
|
||||
return radicalStrokeCount.IsSimplified ? radical.TraditionalRadicalCodePoint : radical.SimplifiedRadicalCodePoint;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal class StringToUtf32Converter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
string text = value as string;
|
||||
|
||||
if (!string.IsNullOrEmpty(text)) return char.ConvertToUtf32(text, 0);
|
||||
else return null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{04E97F21-EF04-441F-83CF-2E71F3AAB089}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<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>
|
||||
@@ -39,6 +39,12 @@
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>UnicodeCharacterInspector.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<UICulture>en-US</UICulture>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
@@ -63,6 +69,9 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="..\AssemblyInfo.Common.cs">
|
||||
<Link>Properties\AssemblyInfo.Common.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
@@ -70,6 +79,15 @@
|
||||
<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>
|
||||
</Compile>
|
||||
<Compile Include="RadicalStrokeCountToCharConverter.cs" />
|
||||
<Compile Include="StringToUtf32Converter.cs" />
|
||||
<Compile Include="Utf32ToNameConverter.cs" />
|
||||
<Compile Include="Utf32ToDisplayTextConverter.cs" />
|
||||
<Compile Include="ZeroToVisibilityConverter.cs" />
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
@@ -93,6 +111,9 @@
|
||||
<Name>UnicodeInformation</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="UnicodeCharacterInspector.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 143 KiB |
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg2">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-1036.3622)"
|
||||
id="layer1">
|
||||
<path
|
||||
d="m 2.5,1.5 2,2"
|
||||
transform="translate(0,1036.3622)"
|
||||
id="path3763"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 1.5,1039.8622 5,0 c -1,2 -3,5 -5,6"
|
||||
id="path3765"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 4.5,14.5 0,-7.5 2,3.5"
|
||||
transform="translate(0,1036.3622)"
|
||||
id="path3767"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1037.8622 0,9 5,0 0,-9 z"
|
||||
id="path3769"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1040.8622 5,0"
|
||||
id="path3771"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 8.5,1043.8622 5,0"
|
||||
id="path3773"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 9.5,1046.8622 c 0,0 1,4 -3,4"
|
||||
id="path3775"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
<path
|
||||
d="m 11.5,1046.8622 0,2 c 0,2 0.5,2 1.5,2 1.5,0 1.5,-1 1.5,-2"
|
||||
id="path3777"
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class Utf32ToDisplayTextConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? UnicodeInfo.GetDisplayText((int)value) : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Unicode;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace UnicodeCharacterInspector
|
||||
{
|
||||
internal sealed class Utf32ToNameConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value != null ? UnicodeInfo.GetName((int)value) : null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -11,7 +11,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
public static void WriteUInt24(this BinaryWriter writer, int value)
|
||||
{
|
||||
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException("value");
|
||||
if (value < 0 || value > 0xFFFFFF) throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
writer.Write((byte)(value));
|
||||
writer.Write((byte)(value >> 8));
|
||||
@@ -27,7 +27,7 @@ namespace System.Unicode.Builder
|
||||
/// <param name="value">The value to write</param>
|
||||
public static void WriteCodePoint(this BinaryWriter writer, int value)
|
||||
{
|
||||
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException("value");
|
||||
if (value < 0 || value > 0x40407F) throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
if (value < 0xA0) writer.Write((byte)value);
|
||||
else if (value < 0x20A0)
|
||||
@@ -50,5 +50,40 @@ namespace System.Unicode.Builder
|
||||
writer.Write((byte)value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Writes a character name alias.</summary>
|
||||
/// <remarks>We assume that character names will not exceed 64 bytes in length.</remarks>
|
||||
/// <param name="writer">The writer to use.</param>
|
||||
/// <param name="nameAlias">The name alias value to write.</param>
|
||||
public static void WriteNameAliasToFile(this BinaryWriter writer, UnicodeNameAlias nameAlias)
|
||||
{
|
||||
writer.Write(nameAlias.Name);
|
||||
writer.Write((byte)nameAlias.Kind);
|
||||
}
|
||||
|
||||
/// <summary>Writes a character name, packing two information bits along with the length.</summary>
|
||||
/// <remarks>We assume that character names will not exceed 128 bytes in length.</remarks>
|
||||
/// <param name="writer">The writer to use.</param>
|
||||
/// <param name="name">The name to write.</param>
|
||||
public static void WriteNamePropertyToFile(this BinaryWriter writer, string name)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(name);
|
||||
if (bytes.Length > 128) throw new InvalidOperationException("Did not expect UTF-8 encoded name to be longer than 128 bytes.");
|
||||
writer.Write((byte)(name.Length - 1)); // The most significant bit will always be cleared, because it will be used for other cases.
|
||||
writer.Write(bytes);
|
||||
}
|
||||
|
||||
/// <summary>Writes a 6 bits length packed with two extra bits.</summary>
|
||||
/// <remarks>The parameters have a restricted range, which must be respected.</remarks>
|
||||
/// <param name="writer">The writer used to perform the operation.</param>
|
||||
/// <param name="extraBits">The value of the two extra bits.</param>
|
||||
/// <param name="length">The length to write.</param>
|
||||
public static void WritePackedLength(this BinaryWriter writer, byte extraBits, int length)
|
||||
{
|
||||
if (extraBits > 3) throw new ArgumentOutOfRangeException(nameof(extraBits));
|
||||
if (length < 1 || length > 64) throw new ArgumentOutOfRangeException(nameof(length));
|
||||
|
||||
writer.Write((byte)((extraBits << 6) | (length - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode.Builder
|
||||
{
|
||||
public static class CharExtensions
|
||||
{
|
||||
public static bool IsHexDigit(this char c)
|
||||
{
|
||||
return c >= '0' && c <= 'f' && (c <= '9' || c <= 'F' && c >= 'A' || c >= 'a');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ namespace System.Unicode.Builder
|
||||
index = 0;
|
||||
}
|
||||
|
||||
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
|
||||
var buffer = stackalloc char[36]; // From the Unicode docs, a decomposition cannot have more than 18 code points.
|
||||
int charIndex = 0;
|
||||
|
||||
while (index < s.Length && charIndex < 35)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,19 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -11,9 +11,12 @@ 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 directoryName = "UCD";
|
||||
public const string UcdDirectoryName = "UCD";
|
||||
public const string UcdArchiveName = "UCD.zip";
|
||||
|
||||
public static readonly string[] ucdRequiredFiles = new[]
|
||||
@@ -21,8 +24,11 @@ namespace System.Unicode.Builder
|
||||
"UnicodeData.txt",
|
||||
"PropList.txt",
|
||||
"DerivedCoreProperties.txt",
|
||||
"Blocks.txt",
|
||||
"Jamo.txt",
|
||||
"CJKRadicals.txt",
|
||||
//"Jamo.txt", // Not used right now, as the hangul syllable algorithm implementation takes care of this.
|
||||
"NameAliases.txt",
|
||||
"NamesList.txt",
|
||||
"Blocks.txt",
|
||||
};
|
||||
|
||||
public static readonly string[] unihanRequiredFiles = new[]
|
||||
@@ -30,20 +36,34 @@ namespace System.Unicode.Builder
|
||||
"Unihan_NumericValues.txt",
|
||||
"Unihan_Readings.txt",
|
||||
"Unihan_Variants.txt",
|
||||
"Unihan_IRGSources.txt",
|
||||
};
|
||||
|
||||
private static byte[] DownloadDataArchive(string archiveName)
|
||||
public static readonly string[] emojiRequiredFiles = new[]
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
return httpClient.GetByteArrayAsync(HttpDataSource.UnicodeCharacterDataUri + archiveName).Result;
|
||||
}
|
||||
"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 void SetHttpMessageHandler(HttpMessageHandler handler)
|
||||
{
|
||||
httpClient = new HttpClient(handler ?? new HttpClientHandler());
|
||||
}
|
||||
|
||||
internal static IDataSource GetDataSource(string archiveName, string directoryName, string[] requiredFiles, bool? shouldDownload, bool? shouldSaveArchive, bool? shouldExtract)
|
||||
internal static HttpClient HttpClient { get { return httpClient ?? (httpClient = new HttpClient()); } }
|
||||
|
||||
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 dataDirectory = Path.Combine(baseDirectory, Program.directoryName);
|
||||
string baseDirectory = Directory.GetCurrentDirectory();
|
||||
string dataDirectory = Path.Combine(baseDirectory, UcdDirectoryName);
|
||||
string dataArchiveFileName = Path.Combine(baseDirectory, archiveName);
|
||||
|
||||
if (shouldDownload != true)
|
||||
@@ -79,18 +99,17 @@ namespace System.Unicode.Builder
|
||||
return new ZipDataSource(File.OpenRead(dataArchiveFileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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)
|
||||
@@ -107,11 +126,6 @@ namespace System.Unicode.Builder
|
||||
return new ZipDataSource(stream);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
stream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -120,20 +134,23 @@ 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, directoryName, 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,37 +1,3 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation.Builder")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation.Builder")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("8dfdee6c-4f0d-4de1-b346-574cb56d2b8b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
@@ -1,136 +1,54 @@
|
||||
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 UnicodeCharacterRange 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 List<int> relatedCodePoints = new List<int>();
|
||||
private readonly List<UnicodeNameAlias> nameAliases = new List<UnicodeNameAlias>();
|
||||
private readonly List<int> crossRerefences = new List<int>();
|
||||
|
||||
public UnicodeCharacterRange CodePointRange { get { return codePointRange; } }
|
||||
public UnicodeCodePointRange CodePointRange { get; }
|
||||
|
||||
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("value");
|
||||
}
|
||||
category = value;
|
||||
}
|
||||
get => category;
|
||||
set => category = Enum.IsDefined(typeof(UnicodeCategory), value) ?
|
||||
value :
|
||||
throw new ArgumentOutOfRangeException(nameof(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; }
|
||||
}
|
||||
|
||||
public ICollection<int> RelatedCodePoints { get { return relatedCodePoints; } }
|
||||
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)
|
||||
: this(new UnicodeCharacterRange(codePoint))
|
||||
: this(new UnicodeCodePointRange(codePoint))
|
||||
{
|
||||
}
|
||||
|
||||
public UnicodeCharacterDataBuilder(UnicodeCharacterRange codePointRange)
|
||||
public UnicodeCharacterDataBuilder(UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
this.codePointRange = codePointRange;
|
||||
CodePointRange = codePointRange;
|
||||
this.category = UnicodeCategory.OtherNotAssigned;
|
||||
}
|
||||
|
||||
@@ -138,71 +56,103 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
return new UnicodeCharacterData
|
||||
(
|
||||
codePointRange,
|
||||
CodePointRange,
|
||||
Name,
|
||||
category,
|
||||
canonicalCombiningClass,
|
||||
bidirectionalClass,
|
||||
characterDecompositionMapping.DecompositionType,
|
||||
characterDecompositionMapping.DecompositionMapping,
|
||||
numericType,
|
||||
numericValue,
|
||||
bidirectionalMirrored,
|
||||
oldName,
|
||||
simpleUpperCaseMapping,
|
||||
simpleLowerCaseMapping,
|
||||
simpleTitleCaseMapping,
|
||||
contributoryProperties,
|
||||
coreProperties,
|
||||
relatedCodePoints.Count > 0 ? relatedCodePoints.ToArray() : null
|
||||
nameAliases.Count > 0 ? nameAliases.ToArray() : UnicodeNameAlias.EmptyArray,
|
||||
Category,
|
||||
CanonicalCombiningClass,
|
||||
BidirectionalClass,
|
||||
CharacterDecompositionMapping.DecompositionType,
|
||||
CharacterDecompositionMapping.DecompositionMapping,
|
||||
NumericType,
|
||||
NumericValue,
|
||||
BidirectionalMirrored,
|
||||
OldName,
|
||||
SimpleUpperCaseMapping,
|
||||
SimpleLowerCaseMapping,
|
||||
SimpleTitleCaseMapping,
|
||||
ContributoryProperties,
|
||||
(int)CoreProperties | (int)EmojiProperties << 20,
|
||||
CrossRerefences.Count > 0 ? CrossRerefences.ToArray() : null
|
||||
);
|
||||
}
|
||||
|
||||
internal void WriteToFile(BinaryWriter writer)
|
||||
{
|
||||
if (nameAliases.Count > 64) throw new InvalidDataException("Cannot handle more than 64 name aliases.");
|
||||
|
||||
UcdFields fields = default(UcdFields);
|
||||
|
||||
if (!codePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
|
||||
if (!CodePointRange.IsSingleCodePoint) fields = UcdFields.CodePointRange;
|
||||
|
||||
if (name != null) fields |= UcdFields.Name;
|
||||
if (Name != null || nameAliases.Count > 0) fields |= UcdFields.Name; // This field combines name and alias.
|
||||
if (category != UnicodeCategory.OtherNotAssigned) fields |= UcdFields.Category;
|
||||
if (canonicalCombiningClass != CanonicalCombiningClass.NotReordered) fields |= UcdFields.CanonicalCombiningClass;
|
||||
/*if (bidirectionalClass != 0)*/fields |= UcdFields.BidirectionalClass;
|
||||
if (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 (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 || 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) writer.Write(name);
|
||||
if ((fields & UcdFields.Name) != 0)
|
||||
{
|
||||
// We write the names by optimizing for the common case.
|
||||
// i.e. Most characters have only one name.
|
||||
// The first 8 bit sequence will encore either the length of the name property alone,
|
||||
// or the number of aliases and a bit indicating the presence of the name property.
|
||||
|
||||
if (nameAliases.Count > 0)
|
||||
{
|
||||
writer.WritePackedLength((byte)(Name != null ? 3 : 2), nameAliases.Count);
|
||||
|
||||
if (Name != null)
|
||||
writer.WriteNamePropertyToFile(Name);
|
||||
|
||||
foreach (var nameAlias in nameAliases)
|
||||
writer.WriteNameAliasToFile(nameAlias);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteNamePropertyToFile(Name);
|
||||
}
|
||||
}
|
||||
if ((fields & UcdFields.Category) != 0) writer.Write((byte)category);
|
||||
if ((fields & UcdFields.CanonicalCombiningClass) != 0) writer.Write((byte)canonicalCombiningClass);
|
||||
if ((fields & UcdFields.BidirectionalClass) != 0) writer.Write((byte)bidirectionalClass);
|
||||
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.CorePropertiesAndEmojiProperties) != 0) writer.WriteUInt24((int)CoreProperties | (int)EmojiProperties << 20);
|
||||
if ((fields & UcdFields.CrossRerefences) != 0)
|
||||
{
|
||||
writer.Write(checked((byte)(crossRerefences.Count - 1)));
|
||||
foreach (int crossReference in crossRerefences)
|
||||
writer.WriteCodePoint(crossReference);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace System.Unicode.Builder
|
||||
hasField = true;
|
||||
goto Completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
@@ -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;
|
||||
@@ -82,9 +82,9 @@ namespace System.Unicode.Builder
|
||||
} while (RefillBuffer());
|
||||
|
||||
hasField = false;
|
||||
Completed: ;
|
||||
Completed:;
|
||||
return hasField;
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadFieldInternal(bool trim)
|
||||
{
|
||||
@@ -121,7 +121,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
byte b = byteBuffer[index];
|
||||
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
{
|
||||
endOffset = index;
|
||||
hasField = false;
|
||||
@@ -192,7 +192,7 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
byte b = byteBuffer[index];
|
||||
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
if (IsNewLineOrComment(b)) // NB: Do not advance to the next byte when end of line has been reached.
|
||||
{
|
||||
hasField = false;
|
||||
return true;
|
||||
|
||||
@@ -4,19 +4,26 @@ 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";
|
||||
public const string CjkRadicalsFileName = "CJKRadicals.txt";
|
||||
public const string NameAliasesFileName = "NameAliases.txt";
|
||||
public const string NamesListFileName = "NamesList.txt";
|
||||
public const string BlocksFileName = "Blocks.txt";
|
||||
public const string UnihanReadingsFileName = "Unihan_Readings.txt";
|
||||
public const string UnihanVariantsFileName = "Unihan_Variants.txt";
|
||||
public const string UnihanNumericValuesFileName = "Unihan_NumericValues.txt";
|
||||
public const string UnihanIrgSourcesFileName = "Unihan_IRGSources.txt";
|
||||
public const string EmojiDataFileName = "emoji-data.txt";
|
||||
|
||||
private static string ParseSimpleCaseMapping(string mapping)
|
||||
{
|
||||
@@ -30,21 +37,44 @@ 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);
|
||||
await ProcessBlocksFile(ucdSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanReadings(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanVariants(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanNumericValues(unihanSource, builder).ConfigureAwait(false);
|
||||
await ProcessUnihanIrgSources(unihanSource, builder).ConfigureAwait(false);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
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), ';'))
|
||||
@@ -53,7 +83,7 @@ namespace System.Unicode.Builder
|
||||
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
var codePoint = new UnicodeCharacterRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
var codePoint = new UnicodeCodePointRange(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
|
||||
string name = reader.ReadField();
|
||||
|
||||
@@ -71,13 +101,13 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
if (rangeStartCodePoint < 0) throw new InvalidDataException("Invalid range data in UnicodeData.txt.");
|
||||
|
||||
codePoint = new UnicodeCharacterRange(rangeStartCodePoint, codePoint.LastCodePoint);
|
||||
codePoint = new UnicodeCodePointRange(rangeStartCodePoint, codePoint.LastCodePoint);
|
||||
|
||||
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
|
||||
name = name.Substring(1, name.Length - 8).ToUpperInvariant(); // Upper-case the name in order to respect unicode naming scheme. (Spec says all names are uppercase ASCII)
|
||||
|
||||
rangeStartCodePoint = -1;
|
||||
}
|
||||
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;
|
||||
@@ -100,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;
|
||||
}
|
||||
@@ -168,10 +197,8 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
ContributoryProperties property;
|
||||
|
||||
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
|
||||
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<ContributoryProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out var property))
|
||||
{
|
||||
builder.SetProperties(property, range);
|
||||
}
|
||||
@@ -185,10 +212,8 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
CoreProperties property;
|
||||
|
||||
var range = UnicodeCharacterRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out property))
|
||||
var range = UnicodeCodePointRange.Parse(reader.ReadTrimmedField());
|
||||
if (EnumHelper<CoreProperties>.TryGetNamedValue(reader.ReadTrimmedField(), out var property))
|
||||
{
|
||||
builder.SetProperties(property, range);
|
||||
}
|
||||
@@ -196,13 +221,181 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessCjkRadicalsFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(CjkRadicalsFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
int lastReadRadical = 0;
|
||||
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
string radicalIndexText = reader.ReadField();
|
||||
bool isSimplified = radicalIndexText[radicalIndexText.Length - 1] == '\'';
|
||||
int radicalIndex = int.Parse(isSimplified ? radicalIndexText.Substring(0, radicalIndexText.Length - 1) : radicalIndexText);
|
||||
|
||||
if (isSimplified ? radicalIndex != lastReadRadical : lastReadRadical + 1 != (lastReadRadical = radicalIndex))
|
||||
throw new InvalidDataException("Did not expect radical number " + radicalIndexText + ".");
|
||||
|
||||
char radicalCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber));
|
||||
char characterCodePoint = checked((char)int.Parse(reader.ReadTrimmedField(), NumberStyles.HexNumber));
|
||||
|
||||
if (!isSimplified && (radicalCodePoint & 0x8000) != 0)
|
||||
throw new InvalidOperationException("Did not expect the radical code point to be higher than U+8000 for radical " + radicalIndex.ToString() + ".");
|
||||
|
||||
if (isSimplified)
|
||||
{
|
||||
builder.SetRadicalInfo(radicalIndex, UpdateRadicalData(builder.GetRadicalInfo(radicalIndex), radicalCodePoint, characterCodePoint));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.SetRadicalInfo(radicalIndex, new CjkRadicalData(radicalCodePoint, characterCodePoint));
|
||||
}
|
||||
}
|
||||
|
||||
if (lastReadRadical != UnicodeInfoBuilder.CjkRadicalCount)
|
||||
throw new InvalidOperationException("There was not enough data for the 214 CJK radicals.");
|
||||
}
|
||||
}
|
||||
|
||||
private static CjkRadicalData UpdateRadicalData(CjkRadicalData traditionalData, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint)
|
||||
{
|
||||
return new CjkRadicalData
|
||||
(
|
||||
traditionalData.TraditionalRadicalCodePoint,
|
||||
traditionalData.TraditionalCharacterCodePoint,
|
||||
simplifiedRadicalCodePoint,
|
||||
simplifiedCharacterCodePoint
|
||||
);
|
||||
}
|
||||
|
||||
private static async Task ProcessNameAliasesFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(NameAliasesFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
var ucd = builder.GetUcd(int.Parse(reader.ReadField(), NumberStyles.HexNumber));
|
||||
|
||||
string name = reader.ReadField();
|
||||
string kindName = reader.ReadField();
|
||||
|
||||
if (!EnumHelper<UnicodeNameAliasKind>.TryGetNamedValue(kindName, out var kind))
|
||||
throw new InvalidDataException("Unrecognized name alias: " + kindName + ".3");
|
||||
|
||||
ucd.NameAliases.Add(new UnicodeNameAlias(name, kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessNamesListFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new StreamReader(await ucdSource.OpenDataFileAsync(NamesListFileName).ConfigureAwait(false), Encoding.UTF8, false))
|
||||
{
|
||||
string line;
|
||||
var characterData = null as UnicodeCharacterDataBuilder;
|
||||
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length == 0)
|
||||
{
|
||||
characterData = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (characterData != null && line.Length > 3 && line[0] == '\t')
|
||||
{
|
||||
if (line[1] == 'x')
|
||||
{
|
||||
// We should get at least 7 characters for a valid line: <tab> "x" <space> [0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]
|
||||
if (line.Length < 7)
|
||||
{
|
||||
characterData = null;
|
||||
continue;
|
||||
}
|
||||
if (line[2] != ' ') throw new InvalidDataException();
|
||||
|
||||
int length;
|
||||
|
||||
if (line[3].IsHexDigit())
|
||||
{
|
||||
length = line.IndexOf(' ', 3);
|
||||
if (length < 0) length = line.Length;
|
||||
length -= 3;
|
||||
|
||||
characterData.CrossRerefences.Add(int.Parse(line.Substring(3, length), NumberStyles.HexNumber));
|
||||
}
|
||||
else if (line[3] == '(')
|
||||
{
|
||||
bool hasBrackets = line[4] == '<';
|
||||
int codePointOffset = line.IndexOf(hasBrackets ? "> - " : "- ", 4);
|
||||
|
||||
if (codePointOffset < 0) throw new InvalidDataException();
|
||||
codePointOffset += hasBrackets ? 4 : 2;
|
||||
|
||||
length = line.IndexOf(')', codePointOffset);
|
||||
if (length < 0) throw new InvalidDataException();
|
||||
length -= codePointOffset;
|
||||
|
||||
characterData.CrossRerefences.Add(int.Parse(line.Substring(codePointOffset, length), NumberStyles.HexNumber));
|
||||
}
|
||||
else throw new InvalidDataException();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[0].IsHexDigit())
|
||||
{
|
||||
int codePoint = int.Parse(line.Substring(0, line.IndexOf('\t')), NumberStyles.HexNumber);
|
||||
// This may return null, but for now, we will ignore code points that are not defined in UnicodeData.txt.
|
||||
characterData = builder.GetUcd(codePoint);
|
||||
// There should be no NamesList.txt entries for code points defined in a range.
|
||||
if (characterData != null && !characterData.CodePointRange.IsSingleCodePoint)
|
||||
{
|
||||
// The only exception to this rule will be when we added the "Noncharacter_Code_Point" property to a few ranges, and we will ignore those.
|
||||
if ((characterData.ContributoryProperties & ContributoryProperties.NonCharacterCodePoint) != 0)
|
||||
characterData = null;
|
||||
else
|
||||
throw new InvalidDataException("Did not expect an NamesList.txt entry for U+" + codePoint.ToString("X4") + ".");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (line[0])
|
||||
{
|
||||
case '@':
|
||||
case ';':
|
||||
case '\t':
|
||||
characterData = null;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDataException("Unrecognized data in NamesList.txt.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessBlocksFile(IDataSource ucdSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnicodeDataFileReader(await ucdSource.OpenDataFileAsync(BlocksFileName).ConfigureAwait(false), ';'))
|
||||
{
|
||||
while (reader.MoveToNextLine())
|
||||
{
|
||||
builder.AddBlockEntry(new UnicodeBlock(UnicodeCharacterRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
|
||||
builder.AddBlockEntry(new UnicodeBlock(UnicodeCodePointRange.Parse(reader.ReadField()), reader.ReadTrimmedField()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -327,5 +520,48 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task ProcessUnihanIrgSources(IDataSource unihanDataSource, UnicodeInfoBuilder builder)
|
||||
{
|
||||
using (var reader = new UnihanDataFileReader(await unihanDataSource.OpenDataFileAsync(UnihanIrgSourcesFileName).ConfigureAwait(false)))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
switch (reader.PropertyName)
|
||||
{
|
||||
case UnihanProperty.kRSUnicode:
|
||||
var entry = builder.GetUnihan(reader.CodePoint);
|
||||
var values = reader.PropertyValue.Split(' ');
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
bool isSimplified = false;
|
||||
int index;
|
||||
|
||||
for (int i = 0; i < value.Length; ++i)
|
||||
{
|
||||
switch (value[i])
|
||||
{
|
||||
case '\'':
|
||||
isSimplified = true;
|
||||
goto case '.';
|
||||
case '.':
|
||||
index = i;
|
||||
goto SeparatorFound;
|
||||
}
|
||||
}
|
||||
throw new InvalidDataException("Failed to decode value for kRSUnicode / Unicode_Radical_Stroke.");
|
||||
|
||||
SeparatorFound:;
|
||||
entry.UnicodeRadicalStrokeCounts.Add(new UnicodeRadicalStrokeCount(byte.Parse(value.Substring(0, index), NumberStyles.None), sbyte.Parse(value.Substring(index + (isSimplified ? 2 : 1)), NumberStyles.AllowLeadingSign), isSimplified));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore unhandled properties for now.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,15 @@ namespace System.Unicode.Builder
|
||||
{
|
||||
internal class UnicodeInfoBuilder
|
||||
{
|
||||
public const int CjkRadicalCount = 214; // The number of radicals (214) shouldn't change in the near future…
|
||||
|
||||
private readonly Version unicodeVersion;
|
||||
private UnicodeCharacterDataBuilder[] ucdEntries = new UnicodeCharacterDataBuilder[10000];
|
||||
private int ucdEntryCount;
|
||||
private UnihanCharacterDataBuilder[] unihanEntries = new UnihanCharacterDataBuilder[10000];
|
||||
private int unihanEntryCount;
|
||||
private List<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
|
||||
private readonly List<UnicodeBlock> blockEntries = new List<UnicodeBlock>(100);
|
||||
private readonly CjkRadicalData[] cjkRadicals = new CjkRadicalData[CjkRadicalCount];
|
||||
|
||||
public UnicodeInfoBuilder(Version unicodeVersion)
|
||||
{
|
||||
@@ -37,7 +40,7 @@ namespace System.Unicode.Builder
|
||||
if (Δ == 0) return index;
|
||||
else if (Δ < 0) maxIndex = index - 1;
|
||||
else minIndex = index + 1;
|
||||
} while (minIndex <= maxIndex);
|
||||
} while (minIndex <= maxIndex);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -117,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);
|
||||
}
|
||||
@@ -137,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);
|
||||
}
|
||||
@@ -176,7 +179,7 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProperties(ContributoryProperties property, UnicodeCharacterRange codePointRange)
|
||||
public void SetProperties(ContributoryProperties property, UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
|
||||
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
|
||||
@@ -192,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;
|
||||
@@ -207,7 +210,7 @@ namespace System.Unicode.Builder
|
||||
}
|
||||
}
|
||||
|
||||
public void SetProperties(CoreProperties property, UnicodeCharacterRange codePointRange)
|
||||
public void SetProperties(CoreProperties property, UnicodeCodePointRange codePointRange)
|
||||
{
|
||||
int firstIndex = FindUcdCodePoint(codePointRange.FirstCodePoint);
|
||||
int lastIndex = FindUcdCodePoint(codePointRange.LastCodePoint);
|
||||
@@ -223,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;
|
||||
@@ -238,10 +241,55 @@ 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));
|
||||
|
||||
cjkRadicals[radicalIndex - 1] = data;
|
||||
}
|
||||
|
||||
public CjkRadicalData GetRadicalInfo(int radicalIndex)
|
||||
{
|
||||
if (radicalIndex < 1 || radicalIndex > CjkRadicalCount) throw new ArgumentOutOfRangeException(nameof(radicalIndex));
|
||||
|
||||
return cjkRadicals[radicalIndex - 1];
|
||||
}
|
||||
|
||||
public void AddBlockEntry(UnicodeBlock block)
|
||||
{
|
||||
blockEntries.Add(block);
|
||||
}
|
||||
}
|
||||
|
||||
//public UnicodeInfo ToUnicodeData()
|
||||
//{
|
||||
@@ -269,20 +317,35 @@ 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]);
|
||||
}
|
||||
writer.Write((byte)CjkRadicalCount);
|
||||
for (int i = 0; i < cjkRadicals.Length; ++i)
|
||||
{
|
||||
var radical = cjkRadicals[i];
|
||||
|
||||
writer.Write((ushort)(radical.HasSimplifiedForm ? 0x8000 | radical.TraditionalRadicalCodePoint : radical.TraditionalRadicalCodePoint));
|
||||
writer.Write((ushort)radical.TraditionalCharacterCodePoint);
|
||||
|
||||
if (radical.HasSimplifiedForm)
|
||||
{
|
||||
writer.Write((ushort)radical.SimplifiedRadicalCodePoint);
|
||||
writer.Write((ushort)radical.SimplifiedCharacterCodePoint);
|
||||
}
|
||||
}
|
||||
writer.WriteCodePoint(unihanEntryCount);
|
||||
for (int i = 0; i < unihanEntryCount; ++i)
|
||||
{
|
||||
|
||||
@@ -1,106 +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)' == '' ">Debug</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="BinaryWriterExtensions.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>
|
||||
@@ -23,6 +23,8 @@ namespace System.Unicode.Builder
|
||||
private string simplifiedVariant;
|
||||
private string traditionalVariant;
|
||||
|
||||
private readonly List<UnicodeRadicalStrokeCount> unicodeRadicalStrokeCounts = new List<UnicodeRadicalStrokeCount>();
|
||||
|
||||
public int CodePoint { get { return codePoint; } }
|
||||
public UnihanNumericType NumericType { get { return numericType; } set { numericType = value; } }
|
||||
public long NumericValue { get { return numericValue; } set { numericValue = value; } }
|
||||
@@ -36,6 +38,7 @@ namespace System.Unicode.Builder
|
||||
public string VietnameseReading { get { return vietnameseReading; } set { vietnameseReading = value; } }
|
||||
public string SimplifiedVariant { get { return simplifiedVariant; } set { simplifiedVariant = value; } }
|
||||
public string TraditionalVariant { get { return traditionalVariant; } set { traditionalVariant = value; } }
|
||||
public IList<UnicodeRadicalStrokeCount> UnicodeRadicalStrokeCounts { get { return unicodeRadicalStrokeCounts; } }
|
||||
|
||||
internal UnihanCharacterDataBuilder(int codePoint)
|
||||
{
|
||||
@@ -49,6 +52,7 @@ namespace System.Unicode.Builder
|
||||
codePoint,
|
||||
numericType,
|
||||
numericValue,
|
||||
unicodeRadicalStrokeCounts.ToArray(),
|
||||
definition,
|
||||
mandarinReading,
|
||||
cantoneseReading,
|
||||
@@ -67,6 +71,14 @@ namespace System.Unicode.Builder
|
||||
UnihanFields fields = default(UnihanFields);
|
||||
|
||||
fields |= (UnihanFields)NumericType;
|
||||
// For now, we have enough bits to encode the length of the array in the field specifier, so we'll do that.
|
||||
// (NB: A quick analysis of the files revealed thare there are almost always exactly one Radical/Stroke count, and occasionally two, yet never more.)
|
||||
if (unicodeRadicalStrokeCounts.Count > 0)
|
||||
{
|
||||
if (unicodeRadicalStrokeCounts.Count == 1) fields |= UnihanFields.UnicodeRadicalStrokeCount;
|
||||
else if (unicodeRadicalStrokeCounts.Count == 2) fields |= UnihanFields.UnicodeRadicalStrokeCountTwice;
|
||||
else fields |= UnihanFields.UnicodeRadicalStrokeCountMore;
|
||||
}
|
||||
if (Definition != null) fields |= UnihanFields.Definition;
|
||||
if (MandarinReading != null) fields |= UnihanFields.MandarinReading;
|
||||
if (CantoneseReading != null) fields |= UnihanFields.CantoneseReading;
|
||||
@@ -82,6 +94,19 @@ namespace System.Unicode.Builder
|
||||
|
||||
writer.WriteCodePoint(UnihanCharacterData.PackCodePoint(codePoint));
|
||||
if ((fields & UnihanFields.OtherNumeric) != 0) writer.Write(numericValue);
|
||||
|
||||
if ((fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0)
|
||||
{
|
||||
if ((fields & (UnihanFields.UnicodeRadicalStrokeCountMore)) == UnihanFields.UnicodeRadicalStrokeCountMore)
|
||||
writer.Write(checked((byte)(unicodeRadicalStrokeCounts.Count - 3)));
|
||||
|
||||
foreach (var radicalStrokeCount in unicodeRadicalStrokeCounts)
|
||||
{
|
||||
writer.Write(radicalStrokeCount.Radical);
|
||||
writer.Write(radicalStrokeCount.RawStrokeCount);
|
||||
}
|
||||
}
|
||||
|
||||
if ((fields & UnihanFields.Definition) != 0) writer.Write(Definition);
|
||||
if ((fields & UnihanFields.MandarinReading) != 0) writer.Write(MandarinReading);
|
||||
if ((fields & UnihanFields.CantoneseReading) != 0) writer.Write(CantoneseReading);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace System.Unicode.Builder
|
||||
public UnihanDataFileReader(Stream stream, bool leaveOpen)
|
||||
{
|
||||
reader = new UnicodeDataFileReader(stream, '\t', leaveOpen);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace System.Unicode.Builder
|
||||
byte[] buffer;
|
||||
|
||||
return new Utf8Buffer(bufferStack.TryPop(out buffer) ? buffer : new byte[100]);
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] buffer;
|
||||
private int length;
|
||||
@@ -40,16 +40,16 @@ namespace System.Unicode.Builder
|
||||
|
||||
private void EnsureExtraCapacity(int count)
|
||||
{
|
||||
if (count < 0) throw new ArgumentOutOfRangeException("requiredExtraCapacity");
|
||||
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (buffer.Length < checked(length + count))
|
||||
Array.Resize(ref buffer, Math.Max(length + count, buffer.Length << 1));
|
||||
}
|
||||
|
||||
public void Append(byte[] value, int startIndex, int count)
|
||||
{
|
||||
if (value == null) throw new ArgumentNullException("value");
|
||||
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException("startIndex");
|
||||
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException("count");
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
if (startIndex >= value.Length) throw new ArgumentOutOfRangeException(nameof(startIndex));
|
||||
if (checked(count += startIndex) > value.Length) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
|
||||
EnsureExtraCapacity(value.Length);
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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,36 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("50337426-e884-4394-9e1a-f6f7a555f5d9")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -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,86 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Unicode.Builder;
|
||||
using System.Text;
|
||||
|
||||
namespace System.Unicode.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class UnicodeDataManagerTests
|
||||
{
|
||||
private const string UcdDirectoryName = "UCD";
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
var directoryName = Path.GetFullPath(UcdDirectoryName);
|
||||
|
||||
if (!Directory.Exists(directoryName))
|
||||
{
|
||||
Directory.CreateDirectory(directoryName);
|
||||
|
||||
string ucdFileName = Path.Combine(directoryName, "UCD.zip");
|
||||
string unihanFileName = Path.Combine(directoryName, "Unihan.zip");
|
||||
|
||||
if (!File.Exists(ucdFileName))
|
||||
{
|
||||
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/UCD.zip", ucdFileName);
|
||||
ZipFile.ExtractToDirectory(ucdFileName, directoryName);
|
||||
}
|
||||
|
||||
if (!File.Exists(unihanFileName))
|
||||
{
|
||||
new WebClient().DownloadFile("http://www.unicode.org/Public/UCD/latest/ucd/Unihan.zip", unihanFileName);
|
||||
ZipFile.ExtractToDirectory(unihanFileName, directoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildDataAsync()
|
||||
{
|
||||
var source = new FileDataSource(UcdDirectoryName);
|
||||
|
||||
var data = (await UnicodeDataProcessor.BuildDataAsync(source, source));
|
||||
|
||||
Assert.AreEqual((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task BuildAndWriteDataAsync()
|
||||
{
|
||||
var source = new FileDataSource(UcdDirectoryName);
|
||||
|
||||
var data = await UnicodeDataProcessor.BuildDataAsync(source, source);
|
||||
|
||||
using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
||||
{
|
||||
data.WriteToStream(stream);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[TestMethod]
|
||||
public void TestCodePointEncoding()
|
||||
{
|
||||
using (var stream = new MemoryStream(4))
|
||||
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; ++i)
|
||||
{
|
||||
writer.WriteCodePoint(i);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
Assert.AreEqual(i, UnicodeInfo.ReadCodePoint(reader));
|
||||
stream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Unicode.Builder;
|
||||
using System.Text;
|
||||
using System.Net.Http;
|
||||
using System.Collections.Generic;
|
||||
using Xunit;
|
||||
using System.Linq;
|
||||
|
||||
namespace System.Unicode.Tests
|
||||
{
|
||||
public class UnicodeInfoBuilderTests
|
||||
{
|
||||
private sealed class FileHttpResponseHandler : HttpMessageHandler
|
||||
{
|
||||
private readonly Dictionary<Uri, string> registeredFiles = new Dictionary<Uri, string>();
|
||||
|
||||
public void RegisterFile(Uri uri, string fileName)
|
||||
{
|
||||
registeredFiles.Add(uri, fileName);
|
||||
}
|
||||
|
||||
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
|
||||
{
|
||||
string fileName;
|
||||
|
||||
if (registeredFiles.TryGetValue(request.RequestUri, out fileName))
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(await Task.Run(() => File.ReadAllBytes(fileName)).ConfigureAwait(false)) };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const string HttpCacheDirectory = "_HttpCache";
|
||||
|
||||
private static async Task RegisterAndDownloadFile(FileHttpResponseHandler handler, string httpCacheDirectory, Uri baseUri, string fileName)
|
||||
{
|
||||
var uri = new Uri(baseUri, fileName);
|
||||
string path = Path.Combine(httpCacheDirectory, fileName);
|
||||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
var data = await httpClient.GetByteArrayAsync(uri).ConfigureAwait(false);
|
||||
|
||||
File.WriteAllBytes(path, data);
|
||||
}
|
||||
}
|
||||
|
||||
handler.RegisterFile(uri, path);
|
||||
}
|
||||
|
||||
public UnicodeInfoBuilderTests()
|
||||
{
|
||||
var httpCacheDirectory = Path.GetFullPath(HttpCacheDirectory);
|
||||
|
||||
if (!Directory.Exists(httpCacheDirectory)) Directory.CreateDirectory(httpCacheDirectory);
|
||||
|
||||
var handler = new FileHttpResponseHandler();
|
||||
|
||||
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.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.WhenAll(emojiTasks));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownloadUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, false, false).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownloadAndSaveUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, false).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractUcdArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UcdArchiveName, Program.UcdDirectoryName, Program.ucdRequiredFiles, true, true, true).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownloadUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, false, false).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DownloadAndSaveUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, false).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtractUnihanArchive()
|
||||
{
|
||||
using (var source = Program.GetDataSourceAsync(Program.UnihanArchiveName, Program.UnihanDirectoryName, Program.ucdRequiredFiles, true, true, true).Result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildDataAsync()
|
||||
{
|
||||
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, emojiSource));
|
||||
|
||||
Assert.Equal((int)'\t', data.GetUcd('\t').CodePointRange.FirstCodePoint);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildAndWriteDataAsync()
|
||||
{
|
||||
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, emojiSource));
|
||||
|
||||
//using (var stream = new DeflateStream(File.Create("ucd.dat"), CompressionLevel.Optimal, false))
|
||||
using (var stream = File.Create("ucd.dat"))
|
||||
{
|
||||
data.WriteToStream(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Fact]
|
||||
public void CodePointEncodingTest()
|
||||
{
|
||||
using (var stream = new MemoryStream(4))
|
||||
using (var writer = new BinaryWriter(stream, Encoding.UTF8, true))
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; ++i)
|
||||
{
|
||||
writer.WriteCodePoint(i);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
Assert.Equal(i, UnicodeInfo.ReadCodePoint(reader));
|
||||
stream.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Unicode;
|
||||
using System.Globalization;
|
||||
using Xunit;
|
||||
|
||||
namespace UnicodeInformation.Tests
|
||||
{
|
||||
public class UnicodeInfoTests
|
||||
{
|
||||
[Fact]
|
||||
public void UnicodeVersionShouldBeTheLatestSupported()
|
||||
{
|
||||
Assert.Equal(new Version(10, 0, 0), UnicodeInfo.UnicodeVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ControlCharactersShouldHaveSpecificDisplayText()
|
||||
{
|
||||
for (int i = 0; i <= 0x20; ++i)
|
||||
{
|
||||
Assert.Equal(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(i));
|
||||
Assert.Equal(char.ConvertFromUtf32(0x2400 + i), UnicodeInfo.GetDisplayText(UnicodeInfo.GetCharInfo(i)));
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("\u0041", 0x0041)]
|
||||
[InlineData("\U0001F600", 0x1F600)]
|
||||
[InlineData("\u00E9", 0x00E9)]
|
||||
public void DisplayTextShouldReturnExpectedResult(string expectedText, int codePoint)
|
||||
{
|
||||
Assert.Equal(expectedText, UnicodeInfo.GetDisplayText(codePoint));
|
||||
}
|
||||
|
||||
[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.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);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Theory]
|
||||
[InlineData('\0')]
|
||||
[InlineData('\uABFF')]
|
||||
[InlineData('\uD7A5')]
|
||||
public void HangulNameShouldFailForNonHangulCodePoints(char codePoint)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
[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.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.NotEmpty(char2A6D6.UnicodeRadicalStrokeCounts);
|
||||
Assert.False(char2A6D6.UnicodeRadicalStrokeCounts[0].IsSimplified);
|
||||
Assert.Equal(214, char2A6D6.UnicodeRadicalStrokeCounts[0].Radical);
|
||||
Assert.Equal(20, char2A6D6.UnicodeRadicalStrokeCounts[0].StrokeCount);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RadicalInfoShouldHaveExpectedResults()
|
||||
{
|
||||
var radical1 = UnicodeInfo.GetCjkRadicalInfo(1);
|
||||
|
||||
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.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);
|
||||
|
||||
Assert.Throws<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(0));
|
||||
Assert.Throws<IndexOutOfRangeException>(() => UnicodeInfo.GetCjkRadicalInfo(215));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MethodGetNameShouldNeverFail()
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; i++)
|
||||
{
|
||||
UnicodeInfo.GetName(i);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MethodGetDisplayTextShouldNeverFail()
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; i++)
|
||||
{
|
||||
UnicodeInfo.GetDisplayText(i);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MethodGetCategoryShouldNeverFail()
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; i++)
|
||||
{
|
||||
UnicodeInfo.GetCategory(i);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MethodGetCharInfoShouldNeverFail()
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; i++)
|
||||
{
|
||||
UnicodeInfo.GetCharInfo(i);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MethodGetCharInfoShouldHaveCoherentResults()
|
||||
{
|
||||
for (int i = 0; i <= 0x10FFFF; i++)
|
||||
{
|
||||
var charInfo = UnicodeInfo.GetCharInfo(i);
|
||||
|
||||
Assert.Equal(charInfo.Name, UnicodeInfo.GetName(i));
|
||||
Assert.Equal(charInfo.Category, UnicodeInfo.GetCategory(i));
|
||||
Assert.Equal(UnicodeInfo.GetDisplayText(charInfo), UnicodeInfo.GetDisplayText(i));
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[Fact]
|
||||
public void UnihanCodePointPackingShouldHaveExpectedResults()
|
||||
{
|
||||
for (int i = 0x3400; i < 0x4E00; ++i)
|
||||
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x4E00; i < 0xA000; ++i)
|
||||
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0xF900; i < 0xFB00; ++i)
|
||||
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x20000; i < 0x2F800; ++i)
|
||||
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
for (int i = 0x2F800; i < 0x30000; ++i)
|
||||
Assert.Equal(i, UnihanCharacterData.UnpackCodePoint(UnihanCharacterData.PackCodePoint(i)));
|
||||
|
||||
// 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));
|
||||
|
||||
// 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,108 +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)' == '' ">Debug</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="UnicodeDataManagerTests.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.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);
|
||||
}
|
||||
}
|
||||
+16
-5
@@ -1,24 +1,32 @@
|
||||
|
||||
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
|
||||
System.Unicode.snk = System.Unicode.snk
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{311FC325-8547-4806-8617-956F1356A92C}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
docs\uci-00.png = docs\uci-00.png
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -45,4 +53,7 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {B155A7AA-DB01-4F49-8985-33AC25BC4B98}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -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")]
|
||||
NonspacingMark,
|
||||
[ValueName("BN"), ValueName("Boundary_Neutral"), Display(Name = "Boundary_Neutral", Description = "most format characters, control codes, or noncharacters")]
|
||||
/// <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,
|
||||
/// <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,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace System.Unicode
|
||||
{
|
||||
internal struct CjkRadicalData
|
||||
{
|
||||
public readonly char TraditionalRadicalCodePoint;
|
||||
public readonly char TraditionalCharacterCodePoint;
|
||||
public readonly char SimplifiedRadicalCodePoint;
|
||||
public readonly char SimplifiedCharacterCodePoint;
|
||||
|
||||
internal CjkRadicalData(char radicalCodePoint, char characterCodePoint)
|
||||
{
|
||||
TraditionalRadicalCodePoint = radicalCodePoint;
|
||||
TraditionalCharacterCodePoint = characterCodePoint;
|
||||
SimplifiedRadicalCodePoint = radicalCodePoint;
|
||||
SimplifiedCharacterCodePoint = characterCodePoint;
|
||||
}
|
||||
|
||||
internal CjkRadicalData(char traditionalRadicalCodePoint, char traditionalCharacterCodePoint, char simplifiedRadicalCodePoint, char simplifiedCharacterCodePoint)
|
||||
{
|
||||
TraditionalRadicalCodePoint = traditionalRadicalCodePoint;
|
||||
TraditionalCharacterCodePoint = traditionalCharacterCodePoint;
|
||||
SimplifiedRadicalCodePoint = simplifiedCharacterCodePoint;
|
||||
SimplifiedCharacterCodePoint = simplifiedCharacterCodePoint;
|
||||
}
|
||||
|
||||
public bool HasSimplifiedForm { get { return SimplifiedRadicalCodePoint != TraditionalRadicalCodePoint || SimplifiedCharacterCodePoint != TraditionalCharacterCodePoint; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
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)
|
||||
{
|
||||
this.radicalIndex = radicalIndex;
|
||||
this.radicalData = radicalData;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +1,37 @@
|
||||
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("text");
|
||||
if (text == null) throw new ArgumentNullException(nameof(text));
|
||||
|
||||
this.text = text;
|
||||
this.current = 0;
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
public static bool TryGetNamedValue(string name, out T value)
|
||||
{
|
||||
return namedValueDictionary.TryGetValue(name, out value);
|
||||
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 string[] GetValueNames(T value) => valueNameDictionary.TryGetValue(value, out string[] names) ? names : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
namespace System.Unicode
|
||||
{
|
||||
internal static class HangulInfo
|
||||
{
|
||||
// Constants defined on page 144 of the Unicode 7.0 Standard (3.12)
|
||||
private const ushort SBase = 0xAC00;
|
||||
private const ushort LBase = 0x1100;
|
||||
private const ushort VBase = 0x1161;
|
||||
private const ushort TBase = 0x11A7;
|
||||
private const int LCount = 19;
|
||||
private const int VCount = 21;
|
||||
private const int TCount = 28;
|
||||
private const int NCount = VCount * TCount;
|
||||
private const int SCount = LCount * NCount;
|
||||
|
||||
private static readonly string[] JamoLTable =
|
||||
{
|
||||
"G", "GG", "N", "D", "DD", "R", "M", "B", "BB",
|
||||
"S", "SS", "", "J", "JJ", "C", "K", "T", "P", "H"
|
||||
};
|
||||
|
||||
private static readonly string[] JamoVTable =
|
||||
{
|
||||
"A", "AE", "YA", "YAE", "EO", "E", "YEO", "YE", "O",
|
||||
"WA", "WAE", "OE", "YO", "U", "WEO", "WE", "WI",
|
||||
"YU", "EU", "YI", "I"
|
||||
};
|
||||
|
||||
private static readonly string[] JamoTTable =
|
||||
{
|
||||
"", "G", "GG", "GS", "N", "NJ", "NH", "D", "L", "LG", "LM",
|
||||
"LB", "LS", "LT", "LP", "LH", "M", "B", "BS",
|
||||
"S", "SS", "NG", "J", "C", "K", "T", "P", "H"
|
||||
};
|
||||
|
||||
// Algorithm defined on page 150 of the Unicode 7.0 Standard (3.12)
|
||||
internal static string GetHangulName(char codePoint)
|
||||
{
|
||||
int sIndex = codePoint - SBase;
|
||||
|
||||
if (sIndex < 0 || sIndex >= SCount) throw new ArgumentOutOfRangeException(nameof(codePoint));
|
||||
|
||||
int lIndex = sIndex / NCount;
|
||||
int vIndex = (sIndex % NCount) / TCount;
|
||||
int tIndex = sIndex % TCount;
|
||||
|
||||
return "HANGUL SYLLABLE " + JamoLTable[lIndex] + JamoVTable[vIndex] + JamoTTable[tIndex];
|
||||
}
|
||||
|
||||
internal static bool IsHangul(int codePoint)
|
||||
{
|
||||
return codePoint >= SBase && codePoint < SBase + SCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,34 +1,6 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("UnicodeInformation")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("UnicodeInformation")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Builder, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
#if DEBUG
|
||||
[assembly: InternalsVisibleTo("UnicodeInformation.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100711da5e71bb2208797ed36597e628c6bf6541b6c157ede943539d19de5104763bd2f42d8c0233ea8fbe7e782d4e2d29c3706a8e8dc1cfa78faabec946a167f7b2b1d396d17a85839ad96f2be930c0efaa893c8b9b6a665bf50ca569b56b9eabf3a69e8274723f85e9d4c3eea1e53dcbbb29a74c78c305e447917daaa6593f1c2")]
|
||||
#endif
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -12,9 +6,9 @@ namespace System.Unicode
|
||||
internal enum UcdFields : ushort
|
||||
{
|
||||
// Not really a field, just here to indicate that the entry is a range
|
||||
CodePointRange = 1,
|
||||
|
||||
Name = 2,
|
||||
CodePointRange = 1,
|
||||
|
||||
Name = 2, // Will stand in for official name as well as related names.
|
||||
Category = 4,
|
||||
CanonicalCombiningClass = 8,
|
||||
BidirectionalClass = 16,
|
||||
@@ -23,7 +17,7 @@ namespace System.Unicode
|
||||
// NumericType / NumericValue : Not exactly a bit mask here… More like [0…3] << 6
|
||||
NumericDecimal = 64,
|
||||
NumericDigit = 128,
|
||||
NumericNumeric = 192,
|
||||
NumericNumeric = 192,
|
||||
|
||||
// This is a yes/no field, so obviously, no extra storage is required for this one…
|
||||
BidirectionalMirrored = 256,
|
||||
@@ -34,6 +28,8 @@ namespace System.Unicode
|
||||
SimpleTitleCaseMapping = 4096,
|
||||
|
||||
ContributoryProperties = 8192,
|
||||
CoreProperties = 16384,
|
||||
CorePropertiesAndEmojiProperties = 16384,
|
||||
|
||||
CrossRerefences = 32768,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
public readonly UnicodeCharacterRange CodePointRange;
|
||||
/// <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(UnicodeCharacterRange codePointRange, 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;
|
||||
|
||||
@@ -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 =
|
||||
@@ -50,10 +47,10 @@ namespace System.Unicode
|
||||
{
|
||||
var dictionary = new Dictionary<string, UnicodeCategory>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var info in categories)
|
||||
foreach (var info in categories)
|
||||
{
|
||||
dictionary.Add(info.ShortName, info.Category);
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,65 +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;
|
||||
private readonly UnicodeCharacterData unicodeCharacterData;
|
||||
private readonly UnihanCharacterData unihanCharacterData;
|
||||
/// <summary>The name of the code point.</summary>
|
||||
private readonly string name;
|
||||
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);
|
||||
|
||||
public string Name
|
||||
/// <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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 unicodeCharacterData.Name == null || unicodeCharacterData.CodePointRange.IsSingleCodePoint ?
|
||||
unicodeCharacterData.Name :
|
||||
unicodeCharacterData.Name + "-" + codePoint.ToString("X4");
|
||||
}
|
||||
if (unihanCharacterDataIndex >= 0)
|
||||
{
|
||||
ref var unihanCharacterData = ref UnihanCharacterData;
|
||||
if (unihanCharacterData.NumericType != UnihanNumericType.None)
|
||||
{
|
||||
return new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return UnicodeCharacterData.NumericValue;
|
||||
}
|
||||
}
|
||||
|
||||
public UnicodeCategory Category { get { return unicodeCharacterData != null ? unicodeCharacterData.Category : UnicodeCategory.OtherNotAssigned; } }
|
||||
public string Block { get { return block ?? "No_Block"; } }
|
||||
public CanonicalCombiningClass CanonicalCombiningClass { get { return unicodeCharacterData.CanonicalCombiningClass; } }
|
||||
public BidirectionalClass BidirectionalClass { get { return unicodeCharacterData.BidirectionalClass; } }
|
||||
public CompatibilityFormattingTag DecompositionType { get { return unicodeCharacterData.DecompositionType; } }
|
||||
public string DecompositionMapping { get { return unicodeCharacterData.DecompositionMapping; } }
|
||||
public UnicodeNumericType NumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType != UnihanNumericType.None ? UnicodeNumericType.Numeric : UnicodeNumericType.None : unicodeCharacterData.NumericType; } }
|
||||
public UnihanNumericType UnihanNumericType { get { return unihanCharacterData != null ? unihanCharacterData.NumericType : UnihanNumericType.None; } }
|
||||
public UnicodeRationalNumber? NumericValue { get { return unihanCharacterData != null && unihanCharacterData.NumericType != UnihanNumericType.None ? new UnicodeRationalNumber(unihanCharacterData.NumericValue, 1) : unicodeCharacterData.NumericValue; } }
|
||||
public bool BidirectionalMirrored { get { return unicodeCharacterData.BidirectionalMirrored; } }
|
||||
public string OldName { get { return unicodeCharacterData.OldName; } }
|
||||
public string SimpleUpperCaseMapping { get { return unicodeCharacterData.SimpleUpperCaseMapping; } }
|
||||
public string SimpleLowerCaseMapping { get { return unicodeCharacterData.SimpleLowerCaseMapping; } }
|
||||
public string SimpleTitleCaseMapping { get { return unicodeCharacterData.SimpleTitleCaseMapping; } }
|
||||
public ContributoryProperties ContributoryProperties { get { return unicodeCharacterData.ContributoryProperties; } }
|
||||
public CoreProperties CoreProperties { get { return unicodeCharacterData.CoreProperties; } }
|
||||
/// <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 => 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 => 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 => 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 => 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 => 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 => new UnicodeRadicalStrokeCountCollection(UnihanCharacterData.UnicodeRadicalStrokeCounts);
|
||||
|
||||
public string Definition { get { return unihanCharacterData?.Definition; } }
|
||||
public string MandarinReading { get { return unihanCharacterData?.MandarinReading; } }
|
||||
public string CantoneseReading { get { return unihanCharacterData?.CantoneseReading; } }
|
||||
public string JapaneseKunReading { get { return unihanCharacterData?.JapaneseKunReading; } }
|
||||
public string JapaneseOnReading { get { return unihanCharacterData?.JapaneseOnReading; } }
|
||||
public string KoreanReading { get { return unihanCharacterData?.KoreanReading; } }
|
||||
public string HangulReading { get { return unihanCharacterData?.HangulReading; } }
|
||||
public string VietnameseReading { get { return unihanCharacterData?.VietnameseReading; } }
|
||||
/// <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 => 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 => 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 => 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 => 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 => 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 => 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 => 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 => UnihanCharacterData.VietnameseReading;
|
||||
|
||||
public string SimplifiedVariant { get { return unihanCharacterData?.SimplifiedVariant; } }
|
||||
public string TraditionalVariant { get { return unihanCharacterData?.TraditionalVariant; } }
|
||||
/// <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 => 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 => 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.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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
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 UnicodeCharacterRange CodePointRange;
|
||||
public readonly UnicodeCodePointRange CodePointRange;
|
||||
public readonly string Name;
|
||||
public readonly UnicodeNameAlias[] NameAliases;
|
||||
public readonly UnicodeCategory Category;
|
||||
public readonly CanonicalCombiningClass CanonicalCombiningClass;
|
||||
public readonly BidirectionalClass BidirectionalClass;
|
||||
@@ -24,33 +20,37 @@ 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[] RelatedCodePoints; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
|
||||
public readonly int[] CrossRerefences; // NB: It seems that parsing NamesList is required in order to provide data for this field ?
|
||||
|
||||
internal UnicodeCharacterData
|
||||
(
|
||||
UnicodeCharacterRange codePointRange,
|
||||
UnicodeCodePointRange codePointRange,
|
||||
string name,
|
||||
UnicodeNameAlias[] nameAliases,
|
||||
UnicodeCategory category,
|
||||
CanonicalCombiningClass canonicalCombiningClass,
|
||||
BidirectionalClass bidirectionalClass,
|
||||
CompatibilityFormattingTag decompositionType,
|
||||
string decompositionMapping,
|
||||
string decompositionMapping,
|
||||
UnicodeNumericType numericType,
|
||||
UnicodeRationalNumber numericValue,
|
||||
bool bidirectionalMirrored,
|
||||
string oldName,
|
||||
string simpleUpperCaseMapping,
|
||||
string simpleUpperCaseMapping,
|
||||
string simpleLowerCaseMapping,
|
||||
string simpleTitleCaseMapping,
|
||||
ContributoryProperties contributoryProperties,
|
||||
CoreProperties coreProperties,
|
||||
int[] relatedCodePoints
|
||||
int corePropertiesAndEmojiProperties,
|
||||
int[] crossRerefences
|
||||
)
|
||||
{
|
||||
this.CodePointRange = codePointRange;
|
||||
this.Name = name;
|
||||
this.NameAliases = nameAliases;
|
||||
this.Category = category;
|
||||
this.CanonicalCombiningClass = canonicalCombiningClass;
|
||||
this.BidirectionalClass = bidirectionalClass;
|
||||
@@ -64,10 +64,10 @@ namespace System.Unicode
|
||||
this.SimpleLowerCaseMapping = simpleLowerCaseMapping;
|
||||
this.SimpleTitleCaseMapping = simpleTitleCaseMapping;
|
||||
this.ContributoryProperties = contributoryProperties;
|
||||
this.CoreProperties = coreProperties;
|
||||
this.RelatedCodePoints = relatedCodePoints;
|
||||
}
|
||||
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?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Unicode
|
||||
{
|
||||
public struct UnicodeCharacterRange : IEnumerable<int>
|
||||
{
|
||||
public struct Enumerator : IEnumerator<int>
|
||||
{
|
||||
private readonly int start;
|
||||
private readonly int end;
|
||||
private int index;
|
||||
|
||||
internal Enumerator(int start, int end)
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.index = start - 1;
|
||||
}
|
||||
|
||||
public int Current { get { return index; } }
|
||||
|
||||
object IEnumerator.Current { get { return index; } }
|
||||
|
||||
void IDisposable.Dispose() { }
|
||||
|
||||
public bool MoveNext() { return index < end && ++index == index; }
|
||||
|
||||
void IEnumerator.Reset() { index = start - 1; }
|
||||
}
|
||||
|
||||
public readonly int FirstCodePoint;
|
||||
public readonly int LastCodePoint;
|
||||
|
||||
public bool IsSingleCodePoint { get { return FirstCodePoint == LastCodePoint; } }
|
||||
|
||||
public UnicodeCharacterRange(int codePoint)
|
||||
{
|
||||
if (codePoint < 0 || codePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("codePoint");
|
||||
|
||||
FirstCodePoint = codePoint;
|
||||
LastCodePoint = codePoint;
|
||||
}
|
||||
|
||||
public UnicodeCharacterRange(int firstCodePoint, int lastCodePoint)
|
||||
{
|
||||
if (firstCodePoint < 0 || firstCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("firstCodePoint");
|
||||
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException("lastCodePoint");
|
||||
|
||||
FirstCodePoint = firstCodePoint;
|
||||
LastCodePoint = lastCodePoint;
|
||||
}
|
||||
|
||||
public bool Contains(int i)
|
||||
{
|
||||
return i >= FirstCodePoint & i <= LastCodePoint;
|
||||
}
|
||||
|
||||
internal int CompareCodePoint(int codePoint)
|
||||
{
|
||||
return FirstCodePoint <= codePoint ? LastCodePoint < codePoint ? 1 : 0 : -1;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return FirstCodePoint == LastCodePoint ? FirstCodePoint.ToString("X4") : FirstCodePoint.ToString("X4") + ".." + LastCodePoint.ToString("X4");
|
||||
}
|
||||
|
||||
public static UnicodeCharacterRange Parse(string s)
|
||||
{
|
||||
int start, end;
|
||||
|
||||
var rangeSeparatorOffset = s.IndexOf("..");
|
||||
|
||||
if (rangeSeparatorOffset == 0) throw new FormatException();
|
||||
else if (rangeSeparatorOffset < 0)
|
||||
{
|
||||
start = end = int.Parse(s, NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = int.Parse(s.Substring(0, rangeSeparatorOffset), NumberStyles.HexNumber);
|
||||
end = int.Parse(s.Substring(rangeSeparatorOffset + 2), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
return new UnicodeCharacterRange(start, end);
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() { return new Enumerator(FirstCodePoint, LastCodePoint); }
|
||||
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
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;
|
||||
this.end = end;
|
||||
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; } }
|
||||
|
||||
/// <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));
|
||||
|
||||
FirstCodePoint = codePoint;
|
||||
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));
|
||||
if (lastCodePoint < firstCodePoint || lastCodePoint > 0x10FFFF) throw new ArgumentOutOfRangeException(nameof(lastCodePoint));
|
||||
|
||||
FirstCodePoint = firstCodePoint;
|
||||
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;
|
||||
}
|
||||
|
||||
internal int CompareCodePoint(int codePoint)
|
||||
{
|
||||
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;
|
||||
|
||||
var rangeSeparatorOffset = s.IndexOf("..");
|
||||
|
||||
if (rangeSeparatorOffset == 0) throw new FormatException();
|
||||
else if (rangeSeparatorOffset < 0)
|
||||
{
|
||||
start = end = int.Parse(s, NumberStyles.HexNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
start = int.Parse(s.Substring(0, rangeSeparatorOffset), NumberStyles.HexNumber);
|
||||
end = int.Parse(s.Substring(rangeSeparatorOffset + 2), NumberStyles.HexNumber);
|
||||
}
|
||||
|
||||
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(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
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 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;
|
||||
|
||||
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]
|
||||
{
|
||||
get { return items[index]; }
|
||||
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; } }
|
||||
|
||||
void ICollection<int>.Add(int item) { throw new NotSupportedException(); }
|
||||
void IList<int>.Insert(int index, int item) { throw new NotSupportedException(); }
|
||||
|
||||
bool ICollection<int>.Remove(int item) { throw new NotSupportedException(); }
|
||||
void IList<int>.RemoveAt(int index) { 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(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -1,34 +1,45 @@
|
||||
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;
|
||||
private static readonly UnicodeCharacterData[] unicodeCharacterData;
|
||||
private static readonly UnihanCharacterData[] unihanCharacterData;
|
||||
private static readonly UnicodeBlock[] blocks;
|
||||
private static readonly CjkRadicalData[] radicals;
|
||||
private static readonly int maxContiguousIndex;
|
||||
private static readonly string[] emojiSequences;
|
||||
|
||||
static UnicodeInfo()
|
||||
{
|
||||
using (var stream = new DeflateStream(typeof(UnicodeInfo).GetTypeInfo().Assembly.GetManifestResourceStream("ucd.dat"), CompressionMode.Decompress, false))
|
||||
{
|
||||
ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out blocks);
|
||||
ReadFromStream(stream, out unicodeVersion, out unicodeCharacterData, out unihanCharacterData, out radicals, out blocks, out maxContiguousIndex);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out UnicodeBlock[] blocks)
|
||||
internal static void ReadFromStream(Stream stream, out Version unicodeVersion, out UnicodeCharacterData[] unicodeCharacterData, out UnihanCharacterData[] unihanCharacterData, out CjkRadicalData[] radicals, out UnicodeBlock[] blocks, out int maxContiguousIndex)
|
||||
{
|
||||
using (var reader = new BinaryReader(stream, Encoding.UTF8))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (reader.ReadByte() != 'U'
|
||||
| reader.ReadByte() != 'C'
|
||||
| reader.ReadByte() != 'D')
|
||||
@@ -36,45 +47,105 @@ 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 (int i = 0; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
for (i = 0; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
unicodeCharacterDataEntries[i] = ReadUnicodeCharacterDataEntry(reader);
|
||||
ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
|
||||
if (unicodeCharacterDataEntries[i].CodePointRange.Contains(i))
|
||||
{
|
||||
mci = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var blockEntries = new UnicodeBlock[reader.ReadByte()];
|
||||
maxContiguousIndex = mci;
|
||||
|
||||
for (int i = 0; i < blockEntries.Length; ++i)
|
||||
for (; i < unicodeCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
blockEntries[i] = ReadBlockEntry(reader);
|
||||
ReadUnicodeCharacterDataEntry(reader, nameBuffer, out unicodeCharacterDataEntries[i]);
|
||||
}
|
||||
|
||||
var blockEntries = new UnicodeBlock[reader.ReadUInt16()];
|
||||
|
||||
for (i = 0; i < blockEntries.Length; ++i)
|
||||
{
|
||||
ReadBlockEntry(reader, out blockEntries[i]);
|
||||
}
|
||||
|
||||
var cjkRadicalEntries = new CjkRadicalData[reader.ReadByte()];
|
||||
|
||||
for (i = 0; i < cjkRadicalEntries.Length; ++i)
|
||||
{
|
||||
ReadCjkRadicalInfo(reader, out cjkRadicalEntries[i]);
|
||||
}
|
||||
|
||||
var unihanCharacterDataEntries = new UnihanCharacterData[ReadCodePoint(reader)];
|
||||
|
||||
for (int i = 0; i < unihanCharacterDataEntries.Length; ++i)
|
||||
for (i = 0; i < unihanCharacterDataEntries.Length; ++i)
|
||||
{
|
||||
unihanCharacterDataEntries[i] = ReadUnihanCharacterDataEntry(reader);
|
||||
ReadUnihanCharacterDataEntry(reader, out unihanCharacterDataEntries[i]);
|
||||
}
|
||||
|
||||
unicodeVersion = fileUnicodeVersion;
|
||||
unicodeCharacterData = unicodeCharacterDataEntries;
|
||||
unihanCharacterData = unihanCharacterDataEntries;
|
||||
radicals = cjkRadicalEntries;
|
||||
blocks = blockEntries;
|
||||
}
|
||||
}
|
||||
|
||||
private static UnicodeCharacterData ReadUnicodeCharacterDataEntry(BinaryReader reader)
|
||||
private static void ReadUnicodeCharacterDataEntry(BinaryReader reader, byte[] nameBuffer, out UnicodeCharacterData value)
|
||||
{
|
||||
var fields = (UcdFields)reader.ReadUInt16();
|
||||
|
||||
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCharacterRange(ReadCodePoint(reader));
|
||||
var codePointRange = (fields & UcdFields.CodePointRange) != 0 ? new UnicodeCodePointRange(ReadCodePoint(reader), ReadCodePoint(reader)) : new UnicodeCodePointRange(ReadCodePoint(reader));
|
||||
|
||||
string name = null;
|
||||
UnicodeNameAlias[] nameAliases = UnicodeNameAlias.EmptyArray;
|
||||
|
||||
// Read all the official names of the character.
|
||||
if ((fields & UcdFields.Name) != 0)
|
||||
{
|
||||
int length = reader.ReadByte();
|
||||
byte @case = (byte)(length & 0xC0);
|
||||
|
||||
if (@case < 0x80) // Handles the case where only the name is present.
|
||||
{
|
||||
length = (length & 0x7F) + 1;
|
||||
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
|
||||
|
||||
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameAliases = new UnicodeNameAlias[(length & 0x3F) + 1];
|
||||
|
||||
if ((@case & 0x40) != 0)
|
||||
{
|
||||
length = reader.ReadByte() + 1;
|
||||
if (length > 128) throw new InvalidDataException("Did not expect names longer than 128 bytes.");
|
||||
if (reader.Read(nameBuffer, 0, length) != length) throw new EndOfStreamException();
|
||||
name = Encoding.UTF8.GetString(nameBuffer, 0, length);
|
||||
}
|
||||
|
||||
for (int i = 0; i < nameAliases.Length; ++i)
|
||||
{
|
||||
nameAliases[i] = new UnicodeNameAlias(reader.ReadString(), (UnicodeNameAliasKind)(reader.ReadByte()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string name = (fields & UcdFields.Name) != 0 ? reader.ReadString() : null;
|
||||
var category = (fields & UcdFields.Category) != 0 ? (UnicodeCategory)reader.ReadByte() : UnicodeCategory.OtherNotAssigned;
|
||||
var canonicalCombiningClass = (fields & UcdFields.CanonicalCombiningClass) != 0 ? (CanonicalCombiningClass)reader.ReadByte() : CanonicalCombiningClass.NotReordered;
|
||||
var bidirectionalClass = (fields & UcdFields.BidirectionalClass) != 0 ? (BidirectionalClass)reader.ReadByte() : 0;
|
||||
@@ -89,12 +160,20 @@ 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;
|
||||
|
||||
return new UnicodeCharacterData
|
||||
if (crossReferences != null)
|
||||
{
|
||||
for (int i = 0; i < crossReferences.Length; ++i)
|
||||
crossReferences[i] = ReadCodePoint(reader);
|
||||
}
|
||||
|
||||
value = new UnicodeCharacterData
|
||||
(
|
||||
codePointRange,
|
||||
name,
|
||||
nameAliases,
|
||||
category,
|
||||
canonicalCombiningClass,
|
||||
bidirectionalClass,
|
||||
@@ -108,12 +187,12 @@ namespace System.Unicode
|
||||
simpleLowerCaseMapping,
|
||||
simpleTitleCaseMapping,
|
||||
contributoryProperties,
|
||||
coreProperties,
|
||||
null
|
||||
corePropertiesAndEmojiProperties,
|
||||
crossReferences
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static UnihanCharacterData ReadUnihanCharacterDataEntry(BinaryReader reader)
|
||||
private static void ReadUnihanCharacterDataEntry(BinaryReader reader, out UnihanCharacterData value)
|
||||
{
|
||||
var fields = (UnihanFields)reader.ReadUInt16();
|
||||
|
||||
@@ -124,6 +203,18 @@ namespace System.Unicode
|
||||
reader.ReadInt64() :
|
||||
0;
|
||||
|
||||
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts = (fields & UnihanFields.UnicodeRadicalStrokeCountMore) != 0 ?
|
||||
new UnicodeRadicalStrokeCount
|
||||
[
|
||||
(fields & UnihanFields.UnicodeRadicalStrokeCountMore) == UnihanFields.UnicodeRadicalStrokeCountMore ?
|
||||
reader.ReadByte() + 3 :
|
||||
((byte)(fields & UnihanFields.UnicodeRadicalStrokeCountMore) >> 2)
|
||||
] :
|
||||
UnicodeRadicalStrokeCount.EmptyArray;
|
||||
|
||||
for (int i = 0; i < unicodeRadicalStrokeCounts.Length; ++i)
|
||||
unicodeRadicalStrokeCounts[i] = new UnicodeRadicalStrokeCount(reader.ReadByte(), reader.ReadByte());
|
||||
|
||||
string definition = (fields & UnihanFields.Definition) != 0 ? reader.ReadString() : null;
|
||||
string mandarinReading = (fields & UnihanFields.MandarinReading) != 0 ? reader.ReadString() : null;
|
||||
string cantoneseReading = (fields & UnihanFields.CantoneseReading) != 0 ? reader.ReadString() : null;
|
||||
@@ -135,11 +226,12 @@ 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,
|
||||
numericValue,
|
||||
unicodeRadicalStrokeCounts,
|
||||
definition,
|
||||
mandarinReading,
|
||||
cantoneseReading,
|
||||
@@ -153,15 +245,23 @@ namespace System.Unicode
|
||||
);
|
||||
}
|
||||
|
||||
private static UnicodeBlock ReadBlockEntry(BinaryReader reader)
|
||||
private static void ReadCjkRadicalInfo(BinaryReader reader, out CjkRadicalData value)
|
||||
{
|
||||
return new UnicodeBlock(new UnicodeCharacterRange(ReadCodePoint(reader), ReadCodePoint(reader)), reader.ReadString());
|
||||
char tr;
|
||||
char tc;
|
||||
|
||||
tr = (char)reader.ReadUInt16();
|
||||
tc = (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 int ReadInt24(BinaryReader reader)
|
||||
{
|
||||
return reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
|
||||
}
|
||||
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) => reader.ReadByte() | ((reader.ReadByte() | (reader.ReadByte() << 8)) << 8);
|
||||
|
||||
#if DEBUG
|
||||
internal static int ReadCodePoint(BinaryReader reader)
|
||||
@@ -183,15 +283,23 @@ namespace System.Unicode
|
||||
else
|
||||
{
|
||||
return 0x40A0 + (((((b & 0x1F) << 8) | reader.ReadByte()) << 8) | reader.ReadByte());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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)
|
||||
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 int BinarySearchUnicodeCodePointIndex(int codePoint)
|
||||
{
|
||||
int minIndex = 0;
|
||||
int maxIndex = unicodeCharacterData.Length - 1;
|
||||
// NB: Due to the strictly ordered nature of the table, we know that a code point can never happen after the index which is the code point itself.
|
||||
// This will greatly reduce the range to scan for characters close to maxContiguousIndex, and will have a lesser impact on other characters.
|
||||
int minIndex = maxContiguousIndex + 1;
|
||||
int maxIndex = codePoint < unicodeCharacterData.Length ? codePoint - 1 : unicodeCharacterData.Length - 1;
|
||||
|
||||
do
|
||||
{
|
||||
@@ -199,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 = unicodeCharacterData.Length - 1].CodePoint)
|
||||
if (unihanCharacterData.Length == 0 || codePoint < unihanCharacterData[minIndex = 0].CodePoint || codePoint > unihanCharacterData[maxIndex = unihanCharacterData.Length - 1].CodePoint)
|
||||
{
|
||||
return null;
|
||||
return -1;
|
||||
}
|
||||
|
||||
do
|
||||
@@ -223,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)
|
||||
@@ -250,42 +358,134 @@ namespace System.Unicode
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static string GetBlockName(int codePoint)
|
||||
internal static ref UnicodeCharacterData GetUnicodeCharacterData(int index)
|
||||
{
|
||||
int i = FindBlockIndex(codePoint);
|
||||
|
||||
return i >= 0 ? blocks[i].Name : null;
|
||||
}
|
||||
|
||||
public static UnicodeCharInfo GetCharInfo(int codePoint)
|
||||
{
|
||||
return new UnicodeCharInfo(codePoint, FindUnicodeCodePoint(codePoint), FindUnihanCodePoint(codePoint), GetBlockName(codePoint));
|
||||
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)
|
||||
=> FindBlockIndex(codePoint) is int i && i >= 0 ?
|
||||
blocks[i].Name :
|
||||
DefaultBlock;
|
||||
|
||||
/// <summary>Gets Unicode information on the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// This method will consolidate the data from a few different sources.
|
||||
/// There are more efficient way of retrieving the data for some properties if only one of those is needed at a time:
|
||||
/// <list type="bullet">
|
||||
/// <listheader>
|
||||
/// <term>Property</term>
|
||||
/// <description>Method</description>
|
||||
/// </listheader>
|
||||
/// <item>
|
||||
/// <term>Name</term>
|
||||
/// <description><see cref="GetName(int)"/></description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Category</term>
|
||||
/// <description><see cref="GetCategory(int)"/></description>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <term>Block</term>
|
||||
/// <description><see cref="GetBlockName(int)"/></description>
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the data must be retrieved.</param>
|
||||
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
|
||||
public static UnicodeCharInfo GetCharInfo(int codePoint)
|
||||
=> new UnicodeCharInfo(codePoint, FindUnicodeCodePointIndex(codePoint), FindUnihanCodePointIndex(codePoint), GetBlockName(codePoint));
|
||||
|
||||
/// <summary>Gets the category of the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// The name referred to is the unicode General_Category property.
|
||||
/// If you only need the category of a character, calling this method is faster than calling <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Category"/>, because there is less information to lookup.
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the category must be retrieved.</param>
|
||||
/// <returns>The category of the code point.</returns>
|
||||
public static UnicodeCategory GetCategory(int codePoint)
|
||||
{
|
||||
var charInfo = FindUnicodeCodePoint(codePoint);
|
||||
=> FindUnicodeCodePointIndex(codePoint) is int unicodeCharacterDataIndex && unicodeCharacterDataIndex >= 0 ?
|
||||
GetUnicodeCharacterData(unicodeCharacterDataIndex).Category :
|
||||
UnicodeCategory.OtherNotAssigned;
|
||||
|
||||
return charInfo != null ? charInfo.Category : UnicodeCategory.OtherNotAssigned;
|
||||
}
|
||||
|
||||
public static string GetDisplayText(UnicodeCharInfo charInfo)
|
||||
{
|
||||
if (charInfo.CodePoint <= 0x0020) return ((char)(0x2400 + charInfo.CodePoint)).ToString();
|
||||
else if (charInfo.Category == UnicodeCategory.NonSpacingMark) return "\u25CC" + char.ConvertFromUtf32(charInfo.CodePoint);
|
||||
else return char.ConvertFromUtf32(charInfo.CodePoint);
|
||||
}
|
||||
/// <summary>Gets a display text for the specified code point.</summary>
|
||||
/// <param name="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>
|
||||
[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);
|
||||
}
|
||||
}
|
||||
|
||||
public static UnicodeBlock[] GetBlocks()
|
||||
private static string GetDisplayText(int codePoint, int unicodeCharacterDataIndex)
|
||||
{
|
||||
return (UnicodeBlock[])blocks.Clone();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>Gets the name of the specified code point.</summary>
|
||||
/// <remarks>
|
||||
/// The name referred to is the unicode Name property.
|
||||
/// If you only need the name of a character, calling this method is faster than calling <see cref="GetCharInfo(int)"/> and retrieving <see cref="UnicodeCharInfo.Name"/>, because there is less information to lookup.
|
||||
/// </remarks>
|
||||
/// <param name="codePoint">The Unicode code point for which the name must be retrieved.</param>
|
||||
/// <returns>The name of the code point, if defined; <see langword="null"/> otherwise.</returns>
|
||||
public static string GetName(int codePoint)
|
||||
=> HangulInfo.IsHangul(codePoint) ?
|
||||
HangulInfo.GetHangulName((char)codePoint) :
|
||||
GetNameInternal(codePoint);
|
||||
|
||||
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);
|
||||
else if (characterData.Name != null) return characterData.Name + "-" + codePoint.ToString("X4");
|
||||
else return null;
|
||||
}
|
||||
|
||||
/// <summary>Returns information for a CJK radical.</summary>
|
||||
/// <param name="radicalIndex">The index of the radical. Must be between 1 and <see cref="CjkRadicalCount"/>.</param>
|
||||
/// <returns>Information on the specified radical.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">The <paramref name="radicalIndex"/> parameter is out of range.</exception>
|
||||
public static CjkRadicalInfo GetCjkRadicalInfo(int radicalIndex)
|
||||
=> 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 => 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() => (UnicodeBlock[])blocks.Clone();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,94 +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)' == '' ">Debug</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>
|
||||
</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>
|
||||
<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="BidirectionalClass.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="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="UnicodeCharacterRange.cs" />
|
||||
<Compile Include="UnicodeCharInfo.cs" />
|
||||
<Compile Include="UnicodeInfo.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>
|
||||
@@ -0,0 +1,27 @@
|
||||
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;
|
||||
Kind = kind;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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;
|
||||
|
||||
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]
|
||||
{
|
||||
get { return items[index]; }
|
||||
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; } }
|
||||
|
||||
void ICollection<UnicodeNameAlias>.Add(UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
void IList<UnicodeNameAlias>.Insert(int index, UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
|
||||
bool ICollection<UnicodeNameAlias>.Remove(UnicodeNameAlias item) { throw new NotSupportedException(); }
|
||||
void IList<UnicodeNameAlias>.RemoveAt(int index) { 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(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
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];
|
||||
|
||||
/// <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;
|
||||
RawStrokeCount = rawStrokeCount;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
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)));
|
||||
}
|
||||
|
||||
/// <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; } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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;
|
||||
|
||||
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]
|
||||
{
|
||||
get { return items[index]; }
|
||||
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; } }
|
||||
|
||||
void ICollection<UnicodeRadicalStrokeCount>.Add(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
void IList<UnicodeRadicalStrokeCount>.Insert(int index, UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
|
||||
bool ICollection<UnicodeRadicalStrokeCount>.Remove(UnicodeRadicalStrokeCount item) { throw new NotSupportedException(); }
|
||||
void IList<UnicodeRadicalStrokeCount>.RemoveAt(int index) { 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(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
}
|
||||
}
|
||||
@@ -1,16 +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 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("s");
|
||||
if (s == null) throw new ArgumentNullException(nameof(s));
|
||||
if (s.Length == 0) throw new ArgumentException();
|
||||
|
||||
int fractionBarIndex = s.IndexOf('/');
|
||||
@@ -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);
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
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;
|
||||
public readonly long NumericValue;
|
||||
public readonly UnicodeRadicalStrokeCount[] UnicodeRadicalStrokeCounts;
|
||||
public readonly string Definition;
|
||||
public readonly string MandarinReading;
|
||||
public readonly string CantoneseReading;
|
||||
@@ -27,6 +22,7 @@ namespace System.Unicode
|
||||
int codePoint,
|
||||
UnihanNumericType numericType,
|
||||
long numericValue,
|
||||
UnicodeRadicalStrokeCount[] unicodeRadicalStrokeCounts,
|
||||
string definition,
|
||||
string mandarinReading,
|
||||
string cantoneseReading,
|
||||
@@ -42,6 +38,7 @@ namespace System.Unicode
|
||||
CodePoint = codePoint;
|
||||
NumericType = numericType;
|
||||
NumericValue = numericValue;
|
||||
UnicodeRadicalStrokeCounts = unicodeRadicalStrokeCounts;
|
||||
Definition = definition;
|
||||
MandarinReading = mandarinReading;
|
||||
CantoneseReading = cantoneseReading;
|
||||
@@ -66,10 +63,10 @@ namespace System.Unicode
|
||||
if (codePoint < 0x2F800) return codePoint - 0x19400;
|
||||
else if (codePoint < 0x30000) return codePoint - 0x10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException("codePoint");
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(nameof(codePoint));
|
||||
}
|
||||
|
||||
internal static int UnpackCodePoint(int packedCodePoint)
|
||||
{
|
||||
@@ -81,7 +78,7 @@ namespace System.Unicode
|
||||
else if (packedCodePoint < 0x1F800) return packedCodePoint - 0xFD00;
|
||||
else if (packedCodePoint < 0x20000) return packedCodePoint + 0x10000;
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("packedCodePoint");
|
||||
throw new ArgumentOutOfRangeException(nameof(packedCodePoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -14,16 +8,21 @@ namespace System.Unicode
|
||||
AccountingNumeric = 2,
|
||||
OtherNumeric = 3,
|
||||
|
||||
Definition = 4,
|
||||
MandarinReading = 8,
|
||||
CantoneseReading = 16,
|
||||
JapaneseKunReading = 32,
|
||||
JapaneseOnReading = 64,
|
||||
KoreanReading = 128,
|
||||
HangulReading = 256,
|
||||
VietnameseReading = 512,
|
||||
// UnicodeRadicalStroke : Not exactly a bit mask…
|
||||
UnicodeRadicalStrokeCount = 4, // Will indicate exactly one value for Unicode_Radical_Stroke.
|
||||
UnicodeRadicalStrokeCountTwice = 8, // Will indicate exactly two values for Unicode_Radical_Stroke.
|
||||
UnicodeRadicalStrokeCountMore = 12, // Will indicate three or more values for Unicode_Radical_Stroke. This combination should never happen in the current files.
|
||||
|
||||
SimplifiedVariant = 1024,
|
||||
TraditionalVariant = 2048,
|
||||
Definition = 16,
|
||||
MandarinReading = 32,
|
||||
CantoneseReading = 64,
|
||||
JapaneseKunReading = 128,
|
||||
JapaneseOnReading = 256,
|
||||
KoreanReading = 512,
|
||||
HangulReading = 1024,
|
||||
VietnameseReading = 2048,
|
||||
|
||||
SimplifiedVariant = 4096,
|
||||
TraditionalVariant = 8192,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,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,
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
|
||||
/// <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;
|
||||
|
||||
@@ -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.
@@ -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
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user