├── .gitattributes ├── .gitignore ├── Chinese.Abstract ├── Chinese.Abstract.csproj ├── ChineseChar.cs ├── ChineseType.cs ├── ChineseWord.cs ├── IWord.cs ├── IWordSource.cs └── PinyinFormat.cs ├── Chinese.Lexicon ├── Chinese.Lexicon.csproj └── Data │ ├── Char.cs │ ├── ChineseDbContext.cs │ ├── Word.cs │ └── WordType.cs ├── Chinese.Region ├── Chinese.Region.csproj ├── City.cs ├── Country.cs ├── Generator.cs ├── Generator.tt ├── ICodeName.cs ├── Model.cs ├── Province.cs └── source │ └── 202201xzqh ├── Chinese.Test ├── Chinese.Test.csproj ├── ChineseConverterTests.cs ├── ChineseCurrencyTests.cs ├── ChineseNumberTests.cs ├── ChineseTokenizerTests.cs └── PinyinTest.cs ├── Chinese.lutconfig ├── Chinese.png ├── Chinese.sln ├── Chinese ├── Chinese.csproj ├── Grammars │ ├── Grammar.cs │ ├── GrammarPart.cs │ └── WordType.cs ├── Lexicon.cs └── Lexicons │ ├── Builtin.cs │ ├── CurrencyLexicon.cs │ ├── NumberLexicon.cs │ └── NumberMode.cs ├── ChineseApp ├── ChineseApp.csproj └── Program.cs ├── LICENSE.md ├── LexiconBuilder ├── LexiconBuilder.csproj └── Program.cs ├── README.md ├── Tests ├── Chinese.Test │ ├── Chinese.Test.csproj │ ├── ConverterTests.cs │ ├── CurrencyTests.cs │ ├── NumberTests.cs │ ├── PinyinTest.cs │ ├── RegionTests.cs │ ├── TokenizerTests.cs │ └── Util │ │ └── MySqlLexicon.cs └── DbCreator.MySql │ ├── .config │ └── dotnet-tools.json │ ├── ApplicationDbContextFactory.cs │ ├── DbCreator.MySql.csproj │ ├── Migrations │ ├── 20221112224627_202211130646.Designer.cs │ ├── 20221112224627_202211130646.cs │ ├── 20221113154648_202211132346.Designer.cs │ ├── 20221113154648_202211132346.cs │ ├── 20230221003235_202302210832.Designer.cs │ ├── 20230221003235_202302210832.cs │ ├── 20230221004748_202302210846.Designer.cs │ ├── 20230221004748_202302210846.cs │ ├── 20230221032034_202302211120.Designer.cs │ ├── 20230221032034_202302211120.cs │ ├── 20230227074215_202302271541.Designer.cs │ ├── 20230227074215_202302271541.cs │ └── ApplicationDbContextModelSnapshot.cs │ └── Program.cs ├── UPDATE_LOG.md ├── lib └── netstandard2.0 │ ├── ChineseConverter.dll │ └── ChnCharInfo.dll └── push.cmd /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Dd]ebugPublic/ 19 | [Rr]elease/ 20 | [Rr]eleases/ 21 | x64/ 22 | x86/ 23 | [Aa][Rr][Mm]/ 24 | [Aa][Rr][Mm]64/ 25 | bld/ 26 | [Bb]in/ 27 | [Oo]bj/ 28 | [Ll]og/ 29 | 30 | # Visual Studio 2015/2017 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # Visual Studio 2017 auto generated files 36 | Generated\ Files/ 37 | 38 | # MSTest test Results 39 | [Tt]est[Rr]esult*/ 40 | [Bb]uild[Ll]og.* 41 | 42 | # NUNIT 43 | *.VisualState.xml 44 | TestResult.xml 45 | 46 | # Build Results of an ATL Project 47 | [Dd]ebugPS/ 48 | [Rr]eleasePS/ 49 | dlldata.c 50 | 51 | # Benchmark Results 52 | BenchmarkDotNet.Artifacts/ 53 | 54 | # .NET Core 55 | project.lock.json 56 | project.fragment.lock.json 57 | artifacts/ 58 | 59 | # StyleCop 60 | StyleCopReport.xml 61 | 62 | # Files built by Visual Studio 63 | *_i.c 64 | *_p.c 65 | *_h.h 66 | *.ilk 67 | *.meta 68 | *.obj 69 | *.iobj 70 | *.pch 71 | *.pdb 72 | *.ipdb 73 | *.pgc 74 | *.pgd 75 | *.rsp 76 | *.sbr 77 | *.tlb 78 | *.tli 79 | *.tlh 80 | *.tmp 81 | *.tmp_proj 82 | *_wpftmp.csproj 83 | *.log 84 | *.vspscc 85 | *.vssscc 86 | .builds 87 | *.pidb 88 | *.svclog 89 | *.scc 90 | 91 | # Chutzpah Test files 92 | _Chutzpah* 93 | 94 | # Visual C++ cache files 95 | ipch/ 96 | *.aps 97 | *.ncb 98 | *.opendb 99 | *.opensdf 100 | *.sdf 101 | *.cachefile 102 | *.VC.db 103 | *.VC.VC.opendb 104 | 105 | # Visual Studio profiler 106 | *.psess 107 | *.vsp 108 | *.vspx 109 | *.sap 110 | 111 | # Visual Studio Trace Files 112 | *.e2e 113 | 114 | # TFS 2012 Local Workspace 115 | $tf/ 116 | 117 | # Guidance Automation Toolkit 118 | *.gpState 119 | 120 | # ReSharper is a .NET coding add-in 121 | _ReSharper*/ 122 | *.[Rr]e[Ss]harper 123 | *.DotSettings.user 124 | 125 | # JustCode is a .NET coding add-in 126 | .JustCode 127 | 128 | # TeamCity is a build add-in 129 | _TeamCity* 130 | 131 | # DotCover is a Code Coverage Tool 132 | *.dotCover 133 | 134 | # AxoCover is a Code Coverage Tool 135 | .axoCover/* 136 | !.axoCover/settings.json 137 | 138 | # Visual Studio code coverage results 139 | *.coverage 140 | *.coveragexml 141 | 142 | # NCrunch 143 | _NCrunch_* 144 | .*crunch*.local.xml 145 | nCrunchTemp_* 146 | 147 | # MightyMoose 148 | *.mm.* 149 | AutoTest.Net/ 150 | 151 | # Web workbench (sass) 152 | .sass-cache/ 153 | 154 | # Installshield output folder 155 | [Ee]xpress/ 156 | 157 | # DocProject is a documentation generator add-in 158 | DocProject/buildhelp/ 159 | DocProject/Help/*.HxT 160 | DocProject/Help/*.HxC 161 | DocProject/Help/*.hhc 162 | DocProject/Help/*.hhk 163 | DocProject/Help/*.hhp 164 | DocProject/Help/Html2 165 | DocProject/Help/html 166 | 167 | # Click-Once directory 168 | publish/ 169 | 170 | # Publish Web Output 171 | *.[Pp]ublish.xml 172 | *.azurePubxml 173 | # Note: Comment the next line if you want to checkin your web deploy settings, 174 | # but database connection strings (with potential passwords) will be unencrypted 175 | *.pubxml 176 | *.publishproj 177 | 178 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 179 | # checkin your Azure Web App publish settings, but sensitive information contained 180 | # in these scripts will be unencrypted 181 | PublishScripts/ 182 | 183 | # NuGet Packages 184 | *.nupkg 185 | # The packages folder can be ignored because of Package Restore 186 | **/[Pp]ackages/* 187 | # except build/, which is used as an MSBuild target. 188 | !**/[Pp]ackages/build/ 189 | # Uncomment if necessary however generally it will be regenerated when needed 190 | #!**/[Pp]ackages/repositories.config 191 | # NuGet v3's project.json files produces more ignorable files 192 | *.nuget.props 193 | *.nuget.targets 194 | 195 | # Microsoft Azure Build Output 196 | csx/ 197 | *.build.csdef 198 | 199 | # Microsoft Azure Emulator 200 | ecf/ 201 | rcf/ 202 | 203 | # Windows Store app package directories and files 204 | AppPackages/ 205 | BundleArtifacts/ 206 | Package.StoreAssociation.xml 207 | _pkginfo.txt 208 | *.appx 209 | 210 | # Visual Studio cache files 211 | # files ending in .cache can be ignored 212 | *.[Cc]ache 213 | # but keep track of directories ending in .cache 214 | !?*.[Cc]ache/ 215 | 216 | # Others 217 | ClientBin/ 218 | ~$* 219 | *~ 220 | *.dbmdl 221 | *.dbproj.schemaview 222 | *.jfm 223 | *.pfx 224 | *.publishsettings 225 | orleans.codegen.cs 226 | 227 | # Including strong name files can present a security risk 228 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 229 | #*.snk 230 | 231 | # Since there are multiple workflows, uncomment next line to ignore bower_components 232 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 233 | #bower_components/ 234 | 235 | # RIA/Silverlight projects 236 | Generated_Code/ 237 | 238 | # Backup & report files from converting an old project file 239 | # to a newer Visual Studio version. Backup files are not needed, 240 | # because we have git ;-) 241 | _UpgradeReport_Files/ 242 | Backup*/ 243 | UpgradeLog*.XML 244 | UpgradeLog*.htm 245 | ServiceFabricBackup/ 246 | *.rptproj.bak 247 | 248 | # SQL Server files 249 | *.mdf 250 | *.ldf 251 | *.ndf 252 | 253 | # Business Intelligence projects 254 | *.rdl.data 255 | *.bim.layout 256 | *.bim_*.settings 257 | *.rptproj.rsuser 258 | *- Backup*.rdl 259 | 260 | # Microsoft Fakes 261 | FakesAssemblies/ 262 | 263 | # GhostDoc plugin setting file 264 | *.GhostDoc.xml 265 | 266 | # Node.js Tools for Visual Studio 267 | .ntvs_analysis.dat 268 | node_modules/ 269 | 270 | # Visual Studio 6 build log 271 | *.plg 272 | 273 | # Visual Studio 6 workspace options file 274 | *.opt 275 | 276 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 277 | *.vbw 278 | 279 | # Visual Studio LightSwitch build output 280 | **/*.HTMLClient/GeneratedArtifacts 281 | **/*.DesktopClient/GeneratedArtifacts 282 | **/*.DesktopClient/ModelManifest.xml 283 | **/*.Server/GeneratedArtifacts 284 | **/*.Server/ModelManifest.xml 285 | _Pvt_Extensions 286 | 287 | # Paket dependency manager 288 | .paket/paket.exe 289 | paket-files/ 290 | 291 | # FAKE - F# Make 292 | .fake/ 293 | 294 | # JetBrains Rider 295 | .idea/ 296 | *.sln.iml 297 | 298 | # CodeRush personal settings 299 | .cr/personal 300 | 301 | # Python Tools for Visual Studio (PTVS) 302 | __pycache__/ 303 | *.pyc 304 | 305 | # Cake - Uncomment if you are using it 306 | # tools/** 307 | # !tools/packages.config 308 | 309 | # Tabs Studio 310 | *.tss 311 | 312 | # Telerik's JustMock configuration file 313 | *.jmconfig 314 | 315 | # BizTalk build output 316 | *.btp.cs 317 | *.btm.cs 318 | *.odx.cs 319 | *.xsd.cs 320 | 321 | # OpenCover UI analysis results 322 | OpenCover/ 323 | 324 | # Azure Stream Analytics local run output 325 | ASALocalRun/ 326 | 327 | # MSBuild Binary and Structured Log 328 | *.binlog 329 | 330 | # NVidia Nsight GPU debugger configuration file 331 | *.nvuser 332 | 333 | # MFractors (Xamarin productivity tool) working folder 334 | .mfractor/ 335 | 336 | # Local History for Visual Studio 337 | .localhistory/ 338 | 339 | # BeatPulse healthcheck temp database 340 | healthchecksdb -------------------------------------------------------------------------------- /Chinese.Abstract/Chinese.Abstract.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0;net7.0;net8.0 5 | enable 6 | enable 7 | 0.0.1 8 | true 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Chinese.Abstract/ChineseChar.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics; 2 | 3 | namespace Chinese; 4 | 5 | [DebuggerDisplay("{Char}")] 6 | public class ChineseChar : ChineseWord 7 | { 8 | public ChineseChar(char ch, ChineseType types, string[] pinyins) 9 | { 10 | Char = ch; 11 | Pinyins = pinyins; 12 | IsPolyphone = Pinyins.Length > 1; 13 | Types = types; 14 | } 15 | 16 | public char Char { get; } 17 | public string[] Pinyins { get; } 18 | public bool IsPolyphone { get; } 19 | public ChineseType Types { get; } 20 | } 21 | -------------------------------------------------------------------------------- /Chinese.Abstract/ChineseType.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese; 2 | 3 | public enum ChineseType 4 | { 5 | Undefined = 0, 6 | 7 | /// 8 | /// 简体中文 9 | /// 10 | Simplified = 1, 11 | 12 | /// 13 | /// 繁体中文 14 | /// 15 | Traditional = 2, 16 | 17 | /// 18 | /// 未简化字 19 | /// 20 | Both = Simplified | Traditional, 21 | } 22 | -------------------------------------------------------------------------------- /Chinese.Abstract/ChineseWord.cs: -------------------------------------------------------------------------------- 1 |  2 | using System.Diagnostics; 3 | 4 | namespace Chinese; 5 | 6 | [DebuggerDisplay("{Simplified}")] 7 | public class ChineseWord : IWord 8 | { 9 | /// 10 | /// 中文字符串 11 | /// 12 | public string? Word 13 | { 14 | set 15 | { 16 | Simplified = value; 17 | Traditional = value; 18 | } 19 | } 20 | /// 21 | /// 简体中文字符串 22 | /// 23 | public string? Simplified { get; set; } 24 | /// 25 | /// 繁体中文字符串 26 | /// 27 | public string? Traditional { get; set; } 28 | 29 | /// 30 | /// 拼音 31 | /// 32 | public string? Pinyin 33 | { 34 | set 35 | { 36 | SimplifiedPinyin = value; 37 | TraditionalPinyin = value; 38 | } 39 | } 40 | /// 41 | /// 简体中文拼音 42 | /// 43 | public string? SimplifiedPinyin { get; set; } 44 | /// 45 | /// 繁体中文拼音 46 | /// 47 | public string? TraditionalPinyin { get; set; } 48 | 49 | /// 50 | /// 额外数据 51 | /// 52 | public object? Tag { get; set; } 53 | 54 | public bool Equals(IWord other) 55 | { 56 | return Simplified == other.Simplified && Traditional == other.Traditional; 57 | } 58 | 59 | public override string ToString() 60 | { 61 | return $"{Simplified}, {Traditional}"; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /Chinese.Abstract/IWord.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese; 2 | 3 | public interface IWord : IEquatable 4 | { 5 | /// 简体中文字符串 6 | /// 7 | string? Simplified { get; } 8 | /// 9 | /// 繁体中文字符串 10 | /// 11 | string? Traditional { get; } 12 | 13 | /// 14 | /// 简体中文拼音 15 | /// 16 | string? SimplifiedPinyin { get; } 17 | /// 18 | /// 繁体中文拼音 19 | /// 20 | string? TraditionalPinyin { get; } 21 | 22 | string? GetString(ChineseType type) 23 | { 24 | if (type == ChineseType.Simplified) return Simplified; 25 | else if (type == ChineseType.Traditional) return Traditional; 26 | else throw new NotSupportedException($"The type is not supported. (type: {type})"); 27 | } 28 | 29 | string? GetPinyin(ChineseType type) 30 | { 31 | if (type == ChineseType.Simplified) return SimplifiedPinyin; 32 | else if (type == ChineseType.Traditional) return TraditionalPinyin; 33 | else throw new NotSupportedException($"The type is not supported. (type: {type})"); 34 | } 35 | 36 | /// 37 | /// 额外数据 38 | /// 39 | object? Tag { get; } 40 | } 41 | -------------------------------------------------------------------------------- /Chinese.Abstract/IWordSource.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese; 2 | 3 | public interface IWordSource 4 | { 5 | string DbFileName { get; } 6 | string ResourceName { get; } 7 | 8 | void CreateDbFile(); 9 | ChineseChar[] GetChars(ChineseType type, IEnumerable chars); 10 | ChineseWord[] GetWords(ChineseType type, IEnumerable chars); 11 | } 12 | 13 | public static class WordSourceExtensions 14 | { 15 | public static bool IsDbFileExsist(this IWordSource @this) => File.Exists(@this.DbFileName); 16 | } 17 | -------------------------------------------------------------------------------- /Chinese.Abstract/PinyinFormat.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese; 2 | 3 | public enum PinyinFormat 4 | { 5 | Default, 6 | WithoutTone, 7 | Phonetic, 8 | InitialConsonant, 9 | } 10 | -------------------------------------------------------------------------------- /Chinese.Lexicon/Chinese.Lexicon.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | preview 8 | 0.7.0-alpha 9 | zmjack 10 | 中文解析通用工具。包括拼音,简繁转换,数字读法,货币读法。 11 | Copyright © nstandard.net 2023 12 | Chinese 13 | LICENSE.md 14 | https://github.com/zmjack/Chinese 15 | Chinese.png 16 | https://github.com/zmjack/Chinese 17 | git 18 | Chinese Pinyin Numerics 19 | true 20 | 21 | 22 | 23 | 24 | 6.0.14 25 | 26 | 27 | 28 | 29 | 30 | 6.0.14 31 | 32 | 33 | 34 | 35 | 36 | \ 37 | True 38 | 39 | 40 | \ 41 | True 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Chinese.Lexicon/Data/Char.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.Diagnostics; 4 | using System.Text.Json; 5 | 6 | namespace Chinese.Data; 7 | 8 | [DebuggerDisplay("{Character}")] 9 | public class Char : IWord, IEquatable 10 | { 11 | [Key] 12 | public int Unicode { get; set; } 13 | 14 | public char Character { get; set; } 15 | 16 | [StringLength(64)] 17 | public string Pinyins { get; set; } 18 | 19 | [NotMapped] 20 | public string[] PinyinsProxy 21 | { 22 | get => JsonSerializer.Deserialize(Pinyins); 23 | set => Pinyins = JsonSerializer.Serialize(value); 24 | } 25 | 26 | public bool IsPolyphone { get; set; } 27 | 28 | public ChineseType Types { get; set; } 29 | 30 | [StringLength(64)] 31 | public string Simplified { get; set; } 32 | 33 | [StringLength(64)] 34 | public string Traditional { get; set; } 35 | 36 | /// 37 | /// 默认拼音 38 | /// 39 | [StringLength(64)] 40 | public string DefaultPinyin { get; set; } 41 | 42 | public bool Sight { get; set; } 43 | 44 | public string SimplifiedPinyin => DefaultPinyin; 45 | public string TraditionalPinyin => DefaultPinyin; 46 | public object Tag => null; 47 | 48 | public bool Equals(Char other) 49 | { 50 | return Unicode == other.Unicode; 51 | } 52 | 53 | public bool Equals(IWord other) 54 | { 55 | throw new NotImplementedException(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Chinese.Lexicon/Data/ChineseDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace Chinese.Data; 4 | 5 | public class ChineseDbContext : DbContext 6 | { 7 | public ChineseDbContext(DbContextOptions options) : base(options) { } 8 | 9 | public DbSet Chars { get; set; } 10 | public DbSet Words { get; set; } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /Chinese.Lexicon/Data/Word.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.ComponentModel.DataAnnotations.Schema; 3 | using System.Diagnostics; 4 | 5 | namespace Chinese.Data; 6 | 7 | [DebuggerDisplay("{Simplified}")] 8 | public class Word : IWord 9 | { 10 | [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] 11 | public Guid Id { get; set; } 12 | 13 | /// 14 | /// 词组类型 15 | /// 16 | public WordType Type { get; set; } 17 | 18 | /// 19 | /// 简体中文字符串 20 | /// 21 | [StringLength(64)] 22 | public string Simplified { get; set; } 23 | 24 | /// 25 | /// 繁体中文字符串 26 | /// 27 | [StringLength(64)] 28 | public string Traditional { get; set; } 29 | 30 | /// 31 | /// 简体中文拼音 32 | /// 33 | [StringLength(64)] 34 | public string SimplifiedPinyin { get; set; } 35 | 36 | /// 37 | /// 繁体中文拼音 38 | /// 39 | [StringLength(64)] 40 | public string TraditionalPinyin { get; set; } 41 | 42 | public int HashCode { get; set; } 43 | 44 | public object Tag => null; 45 | 46 | public bool Equals(IWord other) 47 | { 48 | return Simplified == other.Simplified && Traditional == other.Traditional; 49 | } 50 | 51 | public override int GetHashCode() 52 | { 53 | return HashCode; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Chinese.Lexicon/Data/WordType.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Data; 2 | 3 | public enum WordType 4 | { 5 | Unspecified, 6 | Numberics, 7 | } 8 | -------------------------------------------------------------------------------- /Chinese.Region/Chinese.Region.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | preview 8 | 9 | 10 | 11 | 12 | True 13 | True 14 | Generator.tt 15 | 16 | 17 | 18 | 19 | 20 | TextTemplatingFileGenerator 21 | Generator.cs 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | True 32 | True 33 | Generator.tt 34 | 35 | 36 | True 37 | True 38 | Source.tt 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Chinese.Region/City.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Mainland; 2 | 3 | public class City : ICodeName 4 | { 5 | public required string Code { get; set; } 6 | public required string Name { get; set; } 7 | public required Province Province { get; set; } 8 | public required ICollection Countries { get; set; } 9 | } 10 | -------------------------------------------------------------------------------- /Chinese.Region/Country.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Mainland; 2 | 3 | public class Country : ICodeName 4 | { 5 | public required string Code { get; set; } 6 | public required string Name { get; set; } 7 | public required City City { get; set; } 8 | public Province Province => City.Province; 9 | } 10 | -------------------------------------------------------------------------------- /Chinese.Region/Generator.tt: -------------------------------------------------------------------------------- 1 | <#@ template debug="false" hostspecific="true" language="C#" #> 2 | <#@ assembly name="System.Core" #> 3 | <#@ assembly name="System.Xml" #> 4 | <#@ import namespace="System.Linq" #> 5 | <#@ import namespace="System.Net" #> 6 | <#@ import namespace="System.Text" #> 7 | <#@ import namespace="System.IO" #> 8 | <#@ import namespace="System.Collections.Generic" #> 9 | <#@ import namespace="System.Text.RegularExpressions" #> 10 | <#@ import namespace="System.Xml" #> 11 | <#@ import namespace="System.Xml.XPath" #> 12 | <#@ output extension=".cs" #> 13 | namespace Chinese.Mainland; 14 | 15 | public static class Generator 16 | { 17 | public class Result 18 | { 19 | public required Province[] Provinces { get; set; } 20 | public required City[] Cities { get; set; } 21 | public required Country[] Countries { get; set; } 22 | } 23 | 24 | #pragma warning disable IDE0028 // Simplify collection initialization 25 | public static Result Build() 26 | { 27 | var list = GetModels(); 28 | 29 | Province? province = null; 30 | City? city = null; 31 | 32 | List provinces = []; 33 | List cities = []; 34 | List countries = []; 35 | 36 | foreach (var item in list) 37 | { 38 | if (item.Level == 0) 39 | { 40 | province = new() 41 | { 42 | Code = item.Code, 43 | Name = item.Name, 44 | Cities = new List(), 45 | }; 46 | provinces.Add(province); 47 | } 48 | else if (item.Level == 1) 49 | { 50 | city = new() 51 | { 52 | Code = item.Code, 53 | Name = item.Name, 54 | Province = province!, 55 | Countries = new List(), 56 | }; 57 | cities.Add(city); 58 | (province!.Cities as List)!.Add(city); 59 | } 60 | else if (item.Level == 2) 61 | { 62 | var country = new Country() 63 | { 64 | Code = item.Code, 65 | Name = item.Name, 66 | City = city!, 67 | }; 68 | countries.Add(country); 69 | (city!.Countries as List)!.Add(country); 70 | } 71 | } 72 | 73 | return new Result 74 | { 75 | Provinces = [.. provinces], 76 | Cities = [.. cities], 77 | Countries = [.. countries], 78 | }; 79 | } 80 | #pragma warning restore IDE0028 // Simplify collection initialization 81 | 82 | internal static IEnumerable GetModels() 83 | { 84 | <# 85 | foreach(var model in GetModels()) 86 | { 87 | #> 88 | yield return new Model { Level = <#=model.Level#>, Code = "<#=model.Code#>", Name = "<#=model.Name#>" }; 89 | <# 90 | } 91 | #> 92 | } 93 | } 94 | 95 | <#+ 96 | class Model 97 | { 98 | public int Level { get; set; } 99 | public string Code { get; set; } 100 | public string Name { get; set; } 101 | } 102 | 103 | IEnumerable GetModels() 104 | { 105 | var projectPath = Host.ResolveAssemblyReference("$(ProjectDir)"); 106 | var path = Path.Combine(projectPath, @"source\202201xzqh"); 107 | var html = File.ReadAllText(path); 108 | 109 | var regex = new Regex(@"(.+
)", RegexOptions.Singleline); 110 | var match = regex.Match(html); 111 | var table = match.Groups[1].Value; 112 | 113 | table = table.Replace(Encoding.UTF8.GetString(new byte[] { 0xc2, 0xa0 }), " "); 114 | table = new Regex(@"", RegexOptions.Singleline).Replace(table, ""); 115 | table = new Regex(@"(\r\n)\s+", RegexOptions.Singleline).Replace(table, ""); 116 | table = new Regex(@"(\r\n)\s+", RegexOptions.Singleline).Replace(table, ""); 117 | table = new Regex(@" style='.+?'", RegexOptions.Singleline).Replace(table, ""); 118 | table = new Regex(@" (cellpadding|cellspacing|border|colspan|height|width|class)=.+?(?= |>)", RegexOptions.Singleline).Replace(table, ""); 119 | table = new Regex(@"(.+?)", RegexOptions.Singleline).Replace(table, "$1"); 120 | table = new Regex(@"(.+?)", RegexOptions.Singleline).Replace(table, "$1"); 121 | 122 | var doc = new XmlDocument(); 123 | doc.LoadXml($""" 124 | 125 | {table} 126 | """ 127 | ); 128 | 129 | var list = new List(); 130 | var start = false; 131 | Model pre = null; 132 | 133 | foreach (XmlNode child in doc.DocumentElement.ChildNodes) 134 | { 135 | if (child.ChildNodes[1].InnerText == "行政区划代码") 136 | { 137 | start = true; 138 | continue; 139 | } 140 | 141 | if (start) 142 | { 143 | var col2 = child.ChildNodes[2].InnerText; 144 | if (!string.IsNullOrEmpty(col2)) 145 | { 146 | var level = col2.StartsWith(" ") ? 2 147 | : col2.StartsWith(" ") ? 1 148 | : 0; 149 | var name = col2.Trim(); 150 | 151 | Model item; 152 | if (level == 2 && pre.Level == 0) 153 | { 154 | item = new Model 155 | { 156 | Level = 1, 157 | Code = pre.Code, 158 | Name = pre.Name, 159 | }; 160 | list.Add(item); 161 | pre = item; 162 | } 163 | 164 | var col1 = child.ChildNodes[1].InnerText.Trim(); 165 | if (int.TryParse(col1, out var _code)) 166 | { 167 | var code = _code.ToString(); 168 | item = new() 169 | { 170 | Level = level, 171 | Code = code, 172 | Name = name, 173 | }; 174 | } 175 | else 176 | { 177 | item = new() 178 | { 179 | Level = level, 180 | Code = pre.Code, 181 | Name = name, 182 | }; 183 | } 184 | 185 | list.Add(item); 186 | pre = item; 187 | } 188 | else break; 189 | } 190 | } 191 | 192 | return list; 193 | } 194 | #> 195 | -------------------------------------------------------------------------------- /Chinese.Region/ICodeName.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Mainland; 2 | 3 | public interface ICodeName 4 | { 5 | string Code { get; set; } 6 | string Name { get; set; } 7 | } 8 | -------------------------------------------------------------------------------- /Chinese.Region/Model.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Mainland; 2 | 3 | internal class Model : ICodeName 4 | { 5 | public required int Level { get; set; } 6 | public required string Code { get; set; } 7 | public required string Name { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Chinese.Region/Province.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Mainland; 2 | 3 | public class Province : ICodeName 4 | { 5 | public required string Code { get; set; } 6 | public required string Name { get; set; } 7 | public required ICollection Cities { get; set; } 8 | } 9 | -------------------------------------------------------------------------------- /Chinese.Test/Chinese.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | false 6 | preview 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Chinese.Test/ChineseConverterTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Chinese.Test 4 | { 5 | public class ChineseConverterTests 6 | { 7 | [Fact] 8 | public void Test1() 9 | { 10 | Assert.Equal("免費,跨平臺,開源!", ChineseConverter.ToTraditional("免费,跨平台,开源!")); 11 | Assert.Equal("免费,跨平台,开源!", ChineseConverter.ToSimplified("免費,跨平臺,開源!")); 12 | } 13 | 14 | [Fact] 15 | public void Test2() 16 | { 17 | Assert.Equal("皇后在國王后面。", ChineseConverter.ToTraditional("皇后在国王后面。")); 18 | 19 | var words = new[] 20 | { 21 | new ChineseWord { Simplified = "皇后", Traditional = "皇后", Pinyin = "huang2 hou4" }, 22 | new ChineseWord { Simplified = "后面", Traditional = "後面", Pinyin = "hou4 mian4" }, 23 | }; 24 | 25 | using (new ChineseLexicon(Builtin.ChineseChars, words).BeginScope()) 26 | { 27 | Assert.Equal("皇后在國王後面。", ChineseConverter.ToTraditional("皇后在国王后面。")); 28 | } 29 | } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Chinese.Test/ChineseCurrencyTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Chinese.Test 4 | { 5 | public class ChineseCurrencyTests 6 | { 7 | [Fact] 8 | public void LastZeroTest() 9 | { 10 | ChineseCurrency.GetString(10203040); 11 | 12 | var options = new ChineseNumberOptions { Simplified = false, Upper = false }; 13 | Assert.Equal("一十万元整", ChineseCurrency.GetString(10_0000m, options)); 14 | Assert.Equal("一十亿元整", ChineseCurrency.GetString(10_0000_0000m, options)); 15 | Assert.Equal("一十亿零一元整", ChineseCurrency.GetString(10_0000_0001m, options)); 16 | Assert.Equal("一十亿零一千零一元整", ChineseCurrency.GetString(10_0000_1001m, options)); 17 | Assert.Equal("一十亿零一百万一千零一元整", ChineseCurrency.GetString(10_0100_1001m, options)); 18 | Assert.Equal("一千零二十万三千零四十元整", ChineseCurrency.GetString(1020_3040m, options)); 19 | 20 | Assert.Equal(10_0000m, ChineseCurrency.GetNumber("一十万元整")); 21 | Assert.Equal(10_0000_0000m, ChineseCurrency.GetNumber("一十亿元整")); 22 | Assert.Equal(10_0000_0001m, ChineseCurrency.GetNumber("一十亿零一元整")); 23 | Assert.Equal(10_0000_1001m, ChineseCurrency.GetNumber("一十亿零一千零一元整")); 24 | Assert.Equal(10_0100_1001m, ChineseCurrency.GetNumber("一十亿零一百万一千零一元整")); 25 | Assert.Equal(1020_3040m, ChineseCurrency.GetNumber("一千零二十万三千零四十元整")); 26 | } 27 | 28 | 29 | [Fact] 30 | public void LowerTest() 31 | { 32 | var options = new ChineseNumberOptions { Simplified = false, Upper = false }; 33 | Assert.Equal("一元整", ChineseCurrency.GetString(1, options)); 34 | Assert.Equal("一十万零一元整", ChineseCurrency.GetString(10_0001, options)); 35 | Assert.Equal("一十万零一百零一元整", ChineseCurrency.GetString(10_0101, options)); 36 | Assert.Equal("一十万一千零一元整", ChineseCurrency.GetString(10_1001, options)); 37 | Assert.Equal("一十万一千零一十元整", ChineseCurrency.GetString(10_1010, options)); 38 | Assert.Equal("一十万零一元二角整", ChineseCurrency.GetString(10_0001.2m, options)); 39 | Assert.Equal("一十万零一元二角三分", ChineseCurrency.GetString(10_0001.23m, options)); 40 | Assert.Equal("一十万零一元零三分", ChineseCurrency.GetString(10_0001.03m, options)); 41 | 42 | Assert.Equal(1, ChineseCurrency.GetNumber("一元整")); 43 | Assert.Equal(10_0001, ChineseCurrency.GetNumber("一十万零一元整")); 44 | Assert.Equal(10_0101, ChineseCurrency.GetNumber("一十万零一百零一元整")); 45 | Assert.Equal(10_1001, ChineseCurrency.GetNumber("一十万一千零一元整")); 46 | Assert.Equal(10_1010, ChineseCurrency.GetNumber("一十万一千零一十元整")); 47 | Assert.Equal(10_0001.2m, ChineseCurrency.GetNumber("一十万零一元二角整")); 48 | Assert.Equal(10_0001.23m, ChineseCurrency.GetNumber("一十万零一元二角三分")); 49 | Assert.Equal(10_0001.03m, ChineseCurrency.GetNumber("一十万零一元零三分")); 50 | } 51 | 52 | [Fact] 53 | public void SimplifiedLowerTest() 54 | { 55 | var options = new ChineseNumberOptions { Simplified = true, Upper = false }; 56 | Assert.Equal("一元整", ChineseCurrency.GetString(1, options)); 57 | Assert.Equal("十万零一元整", ChineseCurrency.GetString(10_0001, options)); 58 | Assert.Equal("十万零一百零一元整", ChineseCurrency.GetString(10_0101, options)); 59 | Assert.Equal("十万一千零一元整", ChineseCurrency.GetString(10_1001, options)); 60 | Assert.Equal("十万一千零一十元整", ChineseCurrency.GetString(10_1010, options)); 61 | Assert.Equal("十万零一元二角整", ChineseCurrency.GetString(10_0001.2m, options)); 62 | Assert.Equal("十万零一元二角三分", ChineseCurrency.GetString(10_0001.23m, options)); 63 | Assert.Equal("十万零一元零三分", ChineseCurrency.GetString(10_0001.03m, options)); 64 | 65 | Assert.Equal(1, ChineseCurrency.GetNumber("一元整")); 66 | Assert.Equal(10_0001, ChineseCurrency.GetNumber("十万零一元整")); 67 | Assert.Equal(10_0101, ChineseCurrency.GetNumber("十万零一百零一元整")); 68 | Assert.Equal(10_1001, ChineseCurrency.GetNumber("十万一千零一元整")); 69 | Assert.Equal(10_1010, ChineseCurrency.GetNumber("十万一千零一十元整")); 70 | Assert.Equal(10_0001.2m, ChineseCurrency.GetNumber("十万零一元二角整")); 71 | Assert.Equal(10_0001.23m, ChineseCurrency.GetNumber("十万零一元二角三分")); 72 | Assert.Equal(10_0001.03m, ChineseCurrency.GetNumber("十万零一元零三分")); 73 | } 74 | 75 | [Fact] 76 | public void UpperTest() 77 | { 78 | var options = new ChineseNumberOptions { Simplified = false, Upper = true }; 79 | Assert.Equal("壹圆整", ChineseCurrency.GetString(1, options)); 80 | Assert.Equal("壹拾万零壹圆整", ChineseCurrency.GetString(10_0001, options)); 81 | Assert.Equal("壹拾万零壹佰零壹圆整", ChineseCurrency.GetString(10_0101, options)); 82 | Assert.Equal("壹拾万壹仟零壹圆整", ChineseCurrency.GetString(10_1001, options)); 83 | Assert.Equal("壹拾万壹仟零壹拾圆整", ChineseCurrency.GetString(10_1010, options)); 84 | Assert.Equal("壹拾万零壹圆贰角整", ChineseCurrency.GetString(10_0001.2m, options)); 85 | Assert.Equal("壹拾万零壹圆贰角叁分", ChineseCurrency.GetString(10_0001.23m, options)); 86 | Assert.Equal("壹拾万零壹圆零叁分", ChineseCurrency.GetString(10_0001.03m, options)); 87 | 88 | Assert.Equal(1, ChineseCurrency.GetNumber("壹圆整")); 89 | Assert.Equal(10_0001, ChineseCurrency.GetNumber("壹拾万零壹圆整")); 90 | Assert.Equal(10_0101, ChineseCurrency.GetNumber("壹拾万零壹佰零壹圆整")); 91 | Assert.Equal(10_1001, ChineseCurrency.GetNumber("壹拾万壹仟零壹圆整")); 92 | Assert.Equal(10_1010, ChineseCurrency.GetNumber("壹拾万壹仟零壹拾圆整")); 93 | Assert.Equal(10_0001.2m, ChineseCurrency.GetNumber("壹拾万零壹圆贰角整")); 94 | Assert.Equal(10_0001.23m, ChineseCurrency.GetNumber("壹拾万零壹圆贰角叁分")); 95 | Assert.Equal(10_0001.03m, ChineseCurrency.GetNumber("壹拾万零壹圆零叁分")); 96 | } 97 | 98 | [Fact] 99 | public void SimplifiedUpperTest() 100 | { 101 | var options = new ChineseNumberOptions { Simplified = true, Upper = true }; 102 | Assert.Equal("壹圆整", ChineseCurrency.GetString(1, options)); 103 | Assert.Equal("拾万零壹圆整", ChineseCurrency.GetString(10_0001, options)); 104 | Assert.Equal("拾万零壹佰零壹圆整", ChineseCurrency.GetString(10_0101, options)); 105 | Assert.Equal("拾万壹仟零壹圆整", ChineseCurrency.GetString(10_1001, options)); 106 | Assert.Equal("拾万壹仟零壹拾圆整", ChineseCurrency.GetString(10_1010, options)); 107 | Assert.Equal("拾万零壹圆贰角整", ChineseCurrency.GetString(10_0001.2m, options)); 108 | Assert.Equal("拾万零壹圆贰角叁分", ChineseCurrency.GetString(10_0001.23m, options)); 109 | Assert.Equal("拾万零壹圆零叁分", ChineseCurrency.GetString(10_0001.03m, options)); 110 | 111 | Assert.Equal(1, ChineseCurrency.GetNumber("壹圆整")); 112 | Assert.Equal(10_0001, ChineseCurrency.GetNumber("拾万零壹圆整")); 113 | Assert.Equal(10_0101, ChineseCurrency.GetNumber("拾万零壹佰零壹圆整")); 114 | Assert.Equal(10_1001, ChineseCurrency.GetNumber("拾万壹仟零壹圆整")); 115 | Assert.Equal(10_1010, ChineseCurrency.GetNumber("拾万壹仟零壹拾圆整")); 116 | Assert.Equal(10_0001.2m, ChineseCurrency.GetNumber("拾万零壹圆贰角整")); 117 | Assert.Equal(10_0001.23m, ChineseCurrency.GetNumber("拾万零壹圆贰角叁分")); 118 | Assert.Equal(10_0001.03m, ChineseCurrency.GetNumber("拾万零壹圆零叁分")); 119 | } 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Chinese.Test/ChineseNumberTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Chinese.Test 5 | { 6 | public class ChineseNumberTests 7 | { 8 | [Fact] 9 | public void LowerTest() 10 | { 11 | var options = new ChineseNumberOptions { Simplified = false, Upper = false }; 12 | Assert.Equal("一", ChineseNumber.GetString(1, options)); 13 | Assert.Equal("一十万零一", ChineseNumber.GetString(10_0001, options)); 14 | Assert.Equal("一十万零一百零一", ChineseNumber.GetString(10_0101, options)); 15 | Assert.Equal("一十万一千零一", ChineseNumber.GetString(10_1001, options)); 16 | Assert.Equal("一十万一千零一十", ChineseNumber.GetString(10_1010, options)); 17 | 18 | Assert.Equal(1, ChineseNumber.GetNumber("一")); 19 | Assert.Equal(10_0001, ChineseNumber.GetNumber("一十万零一")); 20 | Assert.Equal(10_0101, ChineseNumber.GetNumber("一十万零一百零一")); 21 | Assert.Equal(10_1001, ChineseNumber.GetNumber("一十万一千零一")); 22 | Assert.Equal(10_1010, ChineseNumber.GetNumber("一十万一千零一十")); 23 | } 24 | 25 | [Fact] 26 | public void SimplifiedLowerTest() 27 | { 28 | var options = new ChineseNumberOptions { Simplified = true, Upper = false }; 29 | Assert.Equal("一", ChineseNumber.GetString(1, options)); 30 | Assert.Equal("十万零一", ChineseNumber.GetString(10_0001, options)); 31 | Assert.Equal("十万零一百零一", ChineseNumber.GetString(10_0101, options)); 32 | Assert.Equal("十万一千零一", ChineseNumber.GetString(10_1001, options)); 33 | Assert.Equal("十万一千零一十", ChineseNumber.GetString(10_1010, options)); 34 | 35 | Assert.Equal(1, ChineseNumber.GetNumber("一")); 36 | Assert.Equal(10_0001, ChineseNumber.GetNumber("十万零一")); 37 | Assert.Equal(10_0101, ChineseNumber.GetNumber("十万零一百零一")); 38 | Assert.Equal(10_1001, ChineseNumber.GetNumber("十万一千零一")); 39 | Assert.Equal(10_1010, ChineseNumber.GetNumber("十万一千零一十")); 40 | } 41 | 42 | [Fact] 43 | public void UpperTest() 44 | { 45 | var options = new ChineseNumberOptions { Simplified = false, Upper = true }; 46 | Assert.Equal("壹", ChineseNumber.GetString(1, options)); 47 | Assert.Equal("壹拾万零壹", ChineseNumber.GetString(10_0001, options)); 48 | Assert.Equal("壹拾万零壹佰零壹", ChineseNumber.GetString(10_0101, options)); 49 | Assert.Equal("壹拾万壹仟零壹", ChineseNumber.GetString(10_1001, options)); 50 | Assert.Equal("壹拾万壹仟零壹拾", ChineseNumber.GetString(10_1010, options)); 51 | 52 | Assert.Equal(1, ChineseNumber.GetNumber("壹")); 53 | Assert.Equal(10_0001, ChineseNumber.GetNumber("壹拾万零壹")); 54 | Assert.Equal(10_0101, ChineseNumber.GetNumber("壹拾万零壹佰零壹")); 55 | Assert.Equal(10_1001, ChineseNumber.GetNumber("壹拾万壹仟零壹")); 56 | Assert.Equal(10_1010, ChineseNumber.GetNumber("壹拾万壹仟零壹拾")); 57 | } 58 | 59 | [Fact] 60 | public void SimplifiedUpperTest() 61 | { 62 | var options = new ChineseNumberOptions { Simplified = true, Upper = true }; 63 | Assert.Equal("壹", ChineseNumber.GetString(1, options)); 64 | Assert.Equal("拾万零壹", ChineseNumber.GetString(10_0001, options)); 65 | Assert.Equal("拾万零壹佰零壹", ChineseNumber.GetString(10_0101, options)); 66 | Assert.Equal("拾万壹仟零壹", ChineseNumber.GetString(10_1001, options)); 67 | Assert.Equal("拾万壹仟零壹拾", ChineseNumber.GetString(10_1010, options)); 68 | 69 | Assert.Equal(1, ChineseNumber.GetNumber("壹")); 70 | Assert.Equal(10_0001, ChineseNumber.GetNumber("拾万零壹")); 71 | Assert.Equal(10_0101, ChineseNumber.GetNumber("拾万零壹佰零壹")); 72 | Assert.Equal(10_1001, ChineseNumber.GetNumber("拾万壹仟零壹")); 73 | Assert.Equal(10_1010, ChineseNumber.GetNumber("拾万壹仟零壹拾")); 74 | } 75 | 76 | [Fact] 77 | public void CodeLowerTest() 78 | { 79 | Assert.Equal("一〇〇〇〇一", ChineseNumber.GetCodeString(10_0001.ToString(), upper: false)); 80 | Assert.Equal("一〇〇一〇一", ChineseNumber.GetCodeString(10_0101.ToString(), upper: false)); 81 | Assert.Equal("一〇一〇〇一", ChineseNumber.GetCodeString(10_1001.ToString(), upper: false)); 82 | Assert.Equal("一〇一〇一〇", ChineseNumber.GetCodeString(10_1010.ToString(), upper: false)); 83 | 84 | Assert.Equal(10_0001.ToString(), ChineseNumber.GetCodeNumber("一〇〇〇〇一")); 85 | Assert.Equal(10_0101.ToString(), ChineseNumber.GetCodeNumber("一〇〇一〇一")); 86 | Assert.Equal(10_1001.ToString(), ChineseNumber.GetCodeNumber("一〇一〇〇一")); 87 | Assert.Equal(10_1010.ToString(), ChineseNumber.GetCodeNumber("一〇一〇一〇")); 88 | } 89 | 90 | [Fact] 91 | public void CodeUpperTest() 92 | { 93 | Assert.Equal("壹零零零零壹", ChineseNumber.GetCodeString(10_0001.ToString(), upper: true)); 94 | Assert.Equal("壹零零壹零壹", ChineseNumber.GetCodeString(10_0101.ToString(), upper: true)); 95 | Assert.Equal("壹零壹零零壹", ChineseNumber.GetCodeString(10_1001.ToString(), upper: true)); 96 | Assert.Equal("壹零壹零壹零", ChineseNumber.GetCodeString(10_1010.ToString(), upper: true)); 97 | 98 | Assert.Equal(10_0001.ToString(), ChineseNumber.GetCodeNumber("壹零零零零壹")); 99 | Assert.Equal(10_0101.ToString(), ChineseNumber.GetCodeNumber("壹零零壹零壹")); 100 | Assert.Equal(10_1001.ToString(), ChineseNumber.GetCodeNumber("壹零壹零零壹")); 101 | Assert.Equal(10_1010.ToString(), ChineseNumber.GetCodeNumber("壹零壹零壹零")); 102 | } 103 | 104 | [Fact] 105 | public void BigIntegerTest() 106 | { 107 | Assert.Equal("一穰二千三百四十五秭六千七百八十九垓零一百二十三京四千五百六十七兆八千九百零一亿二千三百四十五万六千七百八十九", ChineseNumber.GetString(1_2345_6789_0123_4567_8901_2345_6789m)); 108 | Assert.Equal("壹穰贰仟叁佰肆拾伍秭陆仟柒佰捌拾玖垓零壹佰贰拾叁京肆仟伍佰陆拾柒兆捌仟玖佰零壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖", ChineseNumber.GetString(1_2345_6789_0123_4567_8901_2345_6789m, x => x.Upper = true)); 109 | 110 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, ChineseNumber.GetNumber("一穰二千三百四十五秭六千七百八十九垓零一百二十三京四千五百六十七兆八千九百零一亿二千三百四十五万六千七百八十九")); 111 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, ChineseNumber.GetNumber("壹穰贰仟叁佰肆拾伍秭陆仟柒佰捌拾玖垓零壹佰贰拾叁京肆仟伍佰陆拾柒兆捌仟玖佰零壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖")); 112 | } 113 | 114 | [Fact] 115 | public void MutilZeroTest() 116 | { 117 | Assert.Equal("二十亿零一", ChineseNumber.GetString(20_0000_0001)); 118 | Assert.Equal("二十兆零一", ChineseNumber.GetString(20_0000_0000_0001)); 119 | 120 | Assert.Equal(20_0000_0001, ChineseNumber.GetNumber("二十亿零一")); 121 | Assert.Equal(20_0000_0000_0001, ChineseNumber.GetNumber("二十兆零一")); 122 | } 123 | 124 | [Fact] 125 | public void AliasTest() 126 | { 127 | Assert.Equal(22222, ChineseNumber.GetNumber("两万二千两百二十二")); 128 | Assert.Throws(() => ChineseNumber.GetNumber("两")); 129 | Assert.Throws(() => ChineseNumber.GetNumber("两万二千两百二十两")); 130 | } 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Chinese.Test/ChineseTokenizerTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Chinese.Test 4 | { 5 | public class ChineseTokenizerTests 6 | { 7 | [Fact] 8 | public void Test1() 9 | { 10 | using var tokenizer = new ChineseLexicon(Builtin.ChineseChars, new[] 11 | { 12 | new ChineseWord { Simplified = "中国", Traditional = "中國", Pinyin = "zhong1 guo2" }, 13 | new ChineseWord { Word = "北京", Pinyin = "bei3 jing1" }, 14 | new ChineseWord { Simplified = "重庆", Traditional = "重慶", Pinyin = "chong2 qing4" }, 15 | new ChineseWord { Simplified = "直辖市", Traditional = "直轄市", Pinyin = "zhi2 xia2 shi4" }, 16 | }).BeginScope(); 17 | 18 | var sentence = "中国北京是直辖市,重庆也是直辖市。"; 19 | var actual = ChineseTokenizer.SplitWords(ChineseTypes.Simplified, sentence); 20 | var excepted = new[] { "中国", "北京", "是", "直辖市", ",", "重庆", "也", "是", "直辖市", "。" }; 21 | var pinyin = Pinyin.GetString(sentence, PinyinFormat.Phonetic); 22 | 23 | Assert.Equal(excepted, actual); 24 | Assert.Equal("zhōng guó běi jīng shì zhí xiá shì,chóng qìng yě shì zhí xiá shì。", pinyin); 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chinese.Test/PinyinTest.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace Chinese.Test 4 | { 5 | public class PinyinTest 6 | { 7 | [Fact] 8 | public void TmpTest1() 9 | { 10 | } 11 | 12 | [Fact] 13 | public void Test1() 14 | { 15 | var str = "免费,跨平台,开源!"; 16 | Assert.Equal("mian3 fei4,kua4 ping2 tai2,kai1 yuan2!", Pinyin.GetString(str, PinyinFormat.Default)); 17 | Assert.Equal("mian fei,kua ping tai,kai yuan!", Pinyin.GetString(str, PinyinFormat.WithoutTone)); 18 | Assert.Equal("miǎn fèi,kuà píng tái,kāi yuán!", Pinyin.GetString(str, PinyinFormat.Phonetic)); 19 | Assert.Equal("mf,kpt,ky!", Pinyin.GetString(str, PinyinFormat.InitialConsonant)); 20 | } 21 | 22 | [Fact] 23 | public void ChineseLexiconTest1() 24 | { 25 | var str = "他是来自重庆的重量级选手。"; 26 | var pinyin = Pinyin.GetString(str, PinyinFormat.Default); 27 | Assert.Equal("ta1 shi4 lai2 zi4 zhong4 qing4 de5 zhong4 liang4 ji2 xuan3 shou3。", pinyin); 28 | 29 | var words = new ChineseWord[] 30 | { 31 | new ChineseWord { Simplified = "重庆", Traditional = "重慶", Pinyin = "chong2 qing4" }, 32 | new ChineseWord { Simplified = "重量", Traditional = "重量", Pinyin = "zhong4 liang4" }, 33 | }; 34 | 35 | using (new ChineseLexicon(Builtin.ChineseChars, words).BeginScope()) 36 | { 37 | Assert.Equal("ta1 shi4 lai2 zi4 chong2 qing4 de5 zhong4 liang4 ji2 xuan3 shou3。", Pinyin.GetString(str, PinyinFormat.Default)); 38 | } 39 | } 40 | 41 | [Fact] 42 | public void ChineseLexiconTest2() 43 | { 44 | Assert.Equal("服務器中止了服務。", ChineseConverter.ToTraditional("服务器中止了服务。")); 45 | 46 | var words = new[] 47 | { 48 | new ChineseWord { Simplified = "服务器", Traditional = "伺服器", SimplifiedPinyin = "fu2 wu4 qi4", TraditionalPinyin = "si4 fu2 qi4" }, 49 | }; 50 | 51 | using (new ChineseLexicon(Builtin.ChineseChars, words).BeginScope()) 52 | { 53 | Assert.Equal("伺服器中止了服務。", ChineseConverter.ToTraditional("服务器中止了服务。")); 54 | Assert.Equal("fu2 wu4 qi4 zhong1 zhi3 le5 fu2 wu4。", Pinyin.GetString(ChineseTypes.Simplified, "服务器中止了服务。")); 55 | Assert.Equal("si4 fu2 qi4 zhong1 zhi3 le5 fu2 wu4。", Pinyin.GetString(ChineseTypes.Traditional, "伺服器中止了服務。")); 56 | } 57 | } 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Chinese.lutconfig: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 180000 6 | -------------------------------------------------------------------------------- /Chinese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/Chinese/92a75fbdbc4f310257211256d557101544e32b3c/Chinese.png -------------------------------------------------------------------------------- /Chinese.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.1.32210.238 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chinese", "Chinese\Chinese.csproj", "{52E605E4-17C4-4B45-8159-4804653592A7}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9C18C921-F5AD-4B85-AB91-DB23E38991C7}" 9 | ProjectSection(SolutionItems) = preProject 10 | LICENSE.md = LICENSE.md 11 | push.cmd = push.cmd 12 | README.md = README.md 13 | EndProjectSection 14 | EndProject 15 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D9E0D9B3-382B-4C6F-AF78-87C3D1BFA458}" 16 | EndProject 17 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chinese.Test", "Tests\Chinese.Test\Chinese.Test.csproj", "{F1C9D79A-9CC2-4832-BBD7-3040833B30A9}" 18 | EndProject 19 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DbCreator.MySql", "Tests\DbCreator.MySql\DbCreator.MySql.csproj", "{A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}" 20 | EndProject 21 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chinese.Lexicon", "Chinese.Lexicon\Chinese.Lexicon.csproj", "{0A8968BC-6BFD-450D-A912-DF071B3B5A8C}" 22 | EndProject 23 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chinese.Abstract", "Chinese.Abstract\Chinese.Abstract.csproj", "{ED49ED61-0BC1-4679-84B9-A14903064EFF}" 24 | EndProject 25 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChineseApp", "ChineseApp\ChineseApp.csproj", "{D5538A26-2797-417C-8B8D-892799D47A7F}" 26 | EndProject 27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chinese.Region", "Chinese.Region\Chinese.Region.csproj", "{B147BCEE-BF76-4130-BE05-3E223A841213}" 28 | EndProject 29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LexiconBuilder", "LexiconBuilder\LexiconBuilder.csproj", "{48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}" 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Debug|x64 = Debug|x64 35 | Debug|x86 = Debug|x86 36 | Release|Any CPU = Release|Any CPU 37 | Release|x64 = Release|x64 38 | Release|x86 = Release|x86 39 | EndGlobalSection 40 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 41 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|x64.ActiveCfg = Debug|Any CPU 44 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|x64.Build.0 = Debug|Any CPU 45 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|x86.ActiveCfg = Debug|Any CPU 46 | {52E605E4-17C4-4B45-8159-4804653592A7}.Debug|x86.Build.0 = Debug|Any CPU 47 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|x64.ActiveCfg = Release|Any CPU 50 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|x64.Build.0 = Release|Any CPU 51 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|x86.ActiveCfg = Release|Any CPU 52 | {52E605E4-17C4-4B45-8159-4804653592A7}.Release|x86.Build.0 = Release|Any CPU 53 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 54 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|Any CPU.Build.0 = Debug|Any CPU 55 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|x64.ActiveCfg = Debug|Any CPU 56 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|x64.Build.0 = Debug|Any CPU 57 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|x86.ActiveCfg = Debug|Any CPU 58 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Debug|x86.Build.0 = Debug|Any CPU 59 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|Any CPU.ActiveCfg = Release|Any CPU 60 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|Any CPU.Build.0 = Release|Any CPU 61 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|x64.ActiveCfg = Release|Any CPU 62 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|x64.Build.0 = Release|Any CPU 63 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|x86.ActiveCfg = Release|Any CPU 64 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9}.Release|x86.Build.0 = Release|Any CPU 65 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 66 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|Any CPU.Build.0 = Debug|Any CPU 67 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|x64.Build.0 = Debug|Any CPU 69 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Debug|x86.Build.0 = Debug|Any CPU 71 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|Any CPU.ActiveCfg = Release|Any CPU 72 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|Any CPU.Build.0 = Release|Any CPU 73 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|x64.ActiveCfg = Release|Any CPU 74 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|x64.Build.0 = Release|Any CPU 75 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|x86.ActiveCfg = Release|Any CPU 76 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C}.Release|x86.Build.0 = Release|Any CPU 77 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 78 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|Any CPU.Build.0 = Debug|Any CPU 79 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|x64.ActiveCfg = Debug|Any CPU 80 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|x64.Build.0 = Debug|Any CPU 81 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|x86.ActiveCfg = Debug|Any CPU 82 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Debug|x86.Build.0 = Debug|Any CPU 83 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|Any CPU.ActiveCfg = Release|Any CPU 84 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|Any CPU.Build.0 = Release|Any CPU 85 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|x64.ActiveCfg = Release|Any CPU 86 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|x64.Build.0 = Release|Any CPU 87 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|x86.ActiveCfg = Release|Any CPU 88 | {0A8968BC-6BFD-450D-A912-DF071B3B5A8C}.Release|x86.Build.0 = Release|Any CPU 89 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 90 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|Any CPU.Build.0 = Debug|Any CPU 91 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|x64.ActiveCfg = Debug|Any CPU 92 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|x64.Build.0 = Debug|Any CPU 93 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|x86.ActiveCfg = Debug|Any CPU 94 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Debug|x86.Build.0 = Debug|Any CPU 95 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|Any CPU.ActiveCfg = Release|Any CPU 96 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|Any CPU.Build.0 = Release|Any CPU 97 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|x64.ActiveCfg = Release|Any CPU 98 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|x64.Build.0 = Release|Any CPU 99 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|x86.ActiveCfg = Release|Any CPU 100 | {ED49ED61-0BC1-4679-84B9-A14903064EFF}.Release|x86.Build.0 = Release|Any CPU 101 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 102 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|Any CPU.Build.0 = Debug|Any CPU 103 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|x64.ActiveCfg = Debug|Any CPU 104 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|x64.Build.0 = Debug|Any CPU 105 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|x86.ActiveCfg = Debug|Any CPU 106 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Debug|x86.Build.0 = Debug|Any CPU 107 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|Any CPU.ActiveCfg = Release|Any CPU 108 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|Any CPU.Build.0 = Release|Any CPU 109 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|x64.ActiveCfg = Release|Any CPU 110 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|x64.Build.0 = Release|Any CPU 111 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|x86.ActiveCfg = Release|Any CPU 112 | {D5538A26-2797-417C-8B8D-892799D47A7F}.Release|x86.Build.0 = Release|Any CPU 113 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 114 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|Any CPU.Build.0 = Debug|Any CPU 115 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|x64.ActiveCfg = Debug|Any CPU 116 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|x64.Build.0 = Debug|Any CPU 117 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|x86.ActiveCfg = Debug|Any CPU 118 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Debug|x86.Build.0 = Debug|Any CPU 119 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|Any CPU.ActiveCfg = Release|Any CPU 120 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|Any CPU.Build.0 = Release|Any CPU 121 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|x64.ActiveCfg = Release|Any CPU 122 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|x64.Build.0 = Release|Any CPU 123 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|x86.ActiveCfg = Release|Any CPU 124 | {B147BCEE-BF76-4130-BE05-3E223A841213}.Release|x86.Build.0 = Release|Any CPU 125 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 126 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 127 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|x64.ActiveCfg = Debug|Any CPU 128 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|x64.Build.0 = Debug|Any CPU 129 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|x86.ActiveCfg = Debug|Any CPU 130 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Debug|x86.Build.0 = Debug|Any CPU 131 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 132 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|Any CPU.Build.0 = Release|Any CPU 133 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|x64.ActiveCfg = Release|Any CPU 134 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|x64.Build.0 = Release|Any CPU 135 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|x86.ActiveCfg = Release|Any CPU 136 | {48FFAC19-3D9A-4C6F-BB63-3B060536A8C7}.Release|x86.Build.0 = Release|Any CPU 137 | EndGlobalSection 138 | GlobalSection(SolutionProperties) = preSolution 139 | HideSolutionNode = FALSE 140 | EndGlobalSection 141 | GlobalSection(NestedProjects) = preSolution 142 | {F1C9D79A-9CC2-4832-BBD7-3040833B30A9} = {D9E0D9B3-382B-4C6F-AF78-87C3D1BFA458} 143 | {A4AC1F3A-94E5-41AF-A8ED-51480D01D30C} = {D9E0D9B3-382B-4C6F-AF78-87C3D1BFA458} 144 | EndGlobalSection 145 | GlobalSection(ExtensibilityGlobals) = postSolution 146 | SolutionGuid = {B428A319-CD27-4E8D-AAEF-BE69A7F02F09} 147 | EndGlobalSection 148 | EndGlobal 149 | -------------------------------------------------------------------------------- /Chinese/Chinese.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net7.0;net8.0 5 | preview 6 | enable 7 | 0.8.1-alpha 8 | zmjack 9 | 中文解析通用工具。包括拼音,简繁转换,数字读法,货币读法。 10 | Copyright © nstandard.net 2023 11 | Chinese 12 | LICENSE.md 13 | https://github.com/zmjack/Chinese 14 | Chinese.png 15 | https://github.com/zmjack/Chinese 16 | git 17 | Chinese Pinyin Numerics 18 | true 19 | README.md 20 | 21 | 22 | 23 | 24 | True 25 | 26 | 27 | 28 | True 29 | 30 | 31 | 32 | True 33 | \ 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Chinese/Grammars/Grammar.cs: -------------------------------------------------------------------------------- 1 | #if NEW_FEATURE 2 | namespace Chinese.Grammars 3 | { 4 | public class Grammar 5 | { 6 | } 7 | } 8 | #endif 9 | -------------------------------------------------------------------------------- /Chinese/Grammars/GrammarPart.cs: -------------------------------------------------------------------------------- 1 | #if NEW_FEATURE 2 | namespace Chinese.Grammars 3 | { 4 | public class GrammarPart 5 | { 6 | public WordType[][] WordClasses { get; private set; } 7 | private GrammarPart(WordType[][] wordClasses) { WordClasses = wordClasses; } 8 | 9 | public GrammarPart Subject = new GrammarPart(new[] 10 | { 11 | new[] { WordType.Noun }, 12 | new[] { WordType.Pronoun }, 13 | new[] { WordType.Time }, 14 | new[] { WordType.Adjective }, 15 | new[] { WordType.Verb }, 16 | new[] { WordType.Numeral }, 17 | new[] { WordType.Numeral, WordType.Quantity }, 18 | }); 19 | public GrammarPart Predicate = new GrammarPart(new[] 20 | { 21 | new[] { WordType.Verb }, 22 | }); 23 | } 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /Chinese/Grammars/WordType.cs: -------------------------------------------------------------------------------- 1 | #if NEW_FEATURE 2 | using Chinese.Attributes; 3 | 4 | namespace Chinese.Grammars 5 | { 6 | public enum WordType 7 | { 8 | /// 9 | /// 未知词 10 | /// 11 | [Abbreviation("un")] Unknown, 12 | 13 | /// 14 | /// 形容词 15 | /// 16 | [Abbreviation("d")] Adjective, 17 | 18 | /// 19 | /// 连词 20 | /// 21 | [Abbreviation("c")] Conjunction, 22 | 23 | /// 24 | /// 叹词 25 | /// 26 | [Abbreviation("e")] Exclamation, 27 | 28 | /// 29 | /// 成语 30 | /// 31 | [Abbreviation("i")] Idiom, 32 | 33 | /// 34 | /// 数词 35 | /// 36 | [Abbreviation("e")] Numeral, 37 | 38 | /// 39 | /// 名词 40 | /// 41 | [Abbreviation("n")] Noun, 42 | 43 | /// 44 | /// 拟声词 45 | /// 46 | [Abbreviation("o")] Onomatopoeia, 47 | 48 | /// 49 | /// 介词 50 | /// 51 | [Abbreviation("p")] Prepositional, 52 | 53 | /// 54 | /// 量词 55 | /// 56 | [Abbreviation("q")] Quantity, 57 | 58 | /// 59 | /// 代词 60 | /// 61 | [Abbreviation("r")] Pronoun, 62 | 63 | /// 64 | /// 处所词 65 | /// 66 | [Abbreviation("s")] Space, 67 | 68 | /// 69 | /// 时间词 70 | /// 71 | [Abbreviation("t")] Time, 72 | 73 | /// 74 | /// 助词 75 | /// 76 | [Abbreviation("u")] Auxiliary, 77 | 78 | /// 79 | /// 动词 80 | /// 81 | [Abbreviation("v")] Verb, 82 | } 83 | 84 | } 85 | #endif 86 | -------------------------------------------------------------------------------- /Chinese/Lexicon.cs: -------------------------------------------------------------------------------- 1 | using NStandard; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using LinqSharp; 7 | using Chinese.Lexicons; 8 | using Microsoft.Extensions.Caching.Memory; 9 | 10 | namespace Chinese; 11 | 12 | public class Lexicon 13 | { 14 | private static ArgumentException NotSupportedChineseType(ChineseType chineseType, string argument) => new($"不支持的简繁类型({chineseType})。", argument); 15 | 16 | private readonly HashSet _wordSet = []; 17 | private int _maxWordLength = 0; 18 | private const int COMBINE_QUERY_COUNT = 100; 19 | private readonly List> _sourceList = []; 20 | 21 | private static readonly Lazy _number = new(() => new(new())); 22 | public static NumberLexicon Number => _number.Value; 23 | 24 | private static readonly MemoryCache _numberCache = new(new MemoryCacheOptions()); 25 | public static NumberLexicon NumberWith(NumberMode mode) 26 | { 27 | return _numberCache.GetOrCreate(mode, entry => 28 | { 29 | return new NumberLexicon(mode); 30 | }); 31 | } 32 | 33 | private static readonly Lazy _currency = new(() => new(new())); 34 | public static CurrencyLexicon Currency => _currency.Value; 35 | 36 | private static readonly MemoryCache _currencyCache = new(new MemoryCacheOptions()); 37 | public static CurrencyLexicon CurrencyWith(NumberMode mode) 38 | { 39 | return _currencyCache.GetOrCreate(mode, entry => 40 | { 41 | return new CurrencyLexicon(mode); 42 | }); 43 | } 44 | 45 | private IEnumerable> GetSources() 46 | { 47 | yield return _wordSet; 48 | 49 | foreach (var source in _sourceList) 50 | { 51 | yield return source; 52 | } 53 | } 54 | 55 | public Lexicon() 56 | { 57 | } 58 | 59 | public void Add(IWord[] words) 60 | { 61 | foreach (var word in words) 62 | { 63 | _wordSet.Add(word); 64 | var length = Math.Max(word.Simplified.Length, word.Traditional.Length); 65 | if (length > _maxWordLength) 66 | { 67 | _maxWordLength = length; 68 | } 69 | } 70 | } 71 | 72 | public void Add(IQueryable source) 73 | { 74 | _sourceList.Add(source); 75 | 76 | var length = source.Max(x => Math.Max(x.Simplified.Length, x.Traditional.Length)); 77 | if (length > _maxWordLength) 78 | { 79 | _maxWordLength = length; 80 | } 81 | } 82 | 83 | public IEnumerable GetWords(ChineseType chineseType, string sentence) 84 | { 85 | if (sentence.Any()) 86 | { 87 | var length = sentence.Length; 88 | for (int i = 0; i < length; i += COMBINE_QUERY_COUNT) 89 | { 90 | var prev = i - 1; 91 | var start = prev < 0 ? 0 : prev; 92 | var end = i + COMBINE_QUERY_COUNT; 93 | end = end <= length ? end : length; 94 | 95 | var chunk = sentence[start..end]; 96 | foreach (var word in GetSourceWords(chineseType, chunk)) 97 | { 98 | yield return word; 99 | } 100 | } 101 | 102 | var sources = GetSources(); 103 | var last = sentence[^1].ToString(); 104 | foreach (var source in sources) 105 | { 106 | if (chineseType == ChineseType.Simplified) 107 | { 108 | var find = source.FirstOrDefault(x => x.Simplified == last); 109 | if (find is not null) yield return find; 110 | } 111 | else if (chineseType == ChineseType.Traditional) 112 | { 113 | var find = source.FirstOrDefault(x => x.Traditional == last); 114 | if (find is not null) yield return find; 115 | } 116 | else throw NotSupportedChineseType(chineseType, nameof(chineseType)); 117 | } 118 | } 119 | } 120 | 121 | private IEnumerable GetSourceWords(ChineseType chineseType, string chunk) 122 | { 123 | var sources = GetSources(); 124 | foreach (IEnumerable source in sources) 125 | { 126 | IWord[] queryResult; 127 | 128 | if (chineseType == ChineseType.Simplified) 129 | { 130 | queryResult = 131 | [ 132 | .. 133 | source.Filter(h => 134 | { 135 | var exp = h.Empty; 136 | foreach (var window in chunk.Slide(2, true)) 137 | { 138 | var ch0 = window[0]; 139 | var ch1 = window[1]; 140 | 141 | var ch_str = ch0.ToString(); 142 | var str = $"{ch0}{ch1}"; 143 | exp |= h.Where(x => x.Simplified == ch_str) | h.Where(x => x.Simplified.Contains(str)); 144 | } 145 | return exp.DefaultIfEmpty(h.False); 146 | }), 147 | ]; 148 | } 149 | else if (chineseType == ChineseType.Traditional) 150 | { 151 | queryResult = 152 | [ 153 | .. 154 | source.Filter(h => 155 | { 156 | var exp = h.Empty; 157 | foreach (var window in chunk.Slide(2, true)) 158 | { 159 | var ch0 = window[0]; 160 | var ch1 = window[1]; 161 | 162 | var ch_str = ch0.ToString(); 163 | var str = $"{ch0}{ch1}"; 164 | exp |= h.Where(x => x.Traditional == ch_str) | h.Where(x => x.Traditional.Contains(str)); 165 | } 166 | return exp.DefaultIfEmpty(h.False); 167 | }), 168 | ]; 169 | } 170 | else throw NotSupportedChineseType(chineseType, nameof(chineseType)); 171 | 172 | foreach (var word in queryResult) 173 | { 174 | yield return word; 175 | } 176 | } 177 | } 178 | 179 | private readonly char[] _punctuations = ['。', ',', '、', ';', ':', '?', '!', '…', '—', '·', 'ˉ', '¨', '‘', '’', '“', '”', '々', '~', '‖', '∶', '"', ''', '`', '|', '〃', '〔', '〕', '〈', '〉', '《', '》', '「', '」', '『', '』', '.', '〖', '〗', '【', '】', '(', ')', '[', ']', '{', '}']; 180 | 181 | /// 182 | /// 获取分词结果。 183 | /// 184 | /// 185 | /// 186 | /// 187 | public IWord[] SplitWords(string sentence, ChineseType chineseType) 188 | { 189 | var words = GetWords(chineseType, sentence).ToArray(); 190 | 191 | var list = new LinkedList(); 192 | var length = sentence.Length; 193 | 194 | var maxOffset = Math.Min(sentence.Length, _maxWordLength); 195 | var ptext = length - maxOffset; 196 | var maxLengthPerTurn = maxOffset; 197 | int matchLength; 198 | 199 | int Resolve(string part) 200 | { 201 | var word = chineseType switch 202 | { 203 | ChineseType.Simplified => words.FirstOrDefault(x => x.Simplified == part), 204 | ChineseType.Traditional => words.FirstOrDefault(x => x.Traditional == part), 205 | _ => throw NotSupportedChineseType(chineseType, nameof(chineseType)), 206 | }; 207 | 208 | if (word is not null) 209 | { 210 | list.AddFirst(word); 211 | return part.Length; 212 | } 213 | else 214 | { 215 | if (part.Length == 1) 216 | { 217 | list.AddFirst(new ChineseWord 218 | { 219 | Simplified = part, 220 | SimplifiedPinyin = null, 221 | Traditional = part, 222 | TraditionalPinyin = null, 223 | }); 224 | return 1; 225 | } 226 | } 227 | 228 | return 0; 229 | } 230 | 231 | for (; ptext + maxLengthPerTurn >= 0; ptext -= matchLength) 232 | { 233 | matchLength = 1; 234 | for (var i = ptext > 0 ? 0 : -ptext; i < maxLengthPerTurn;) 235 | { 236 | var part = sentence.Substring(ptext + i, maxLengthPerTurn - i); 237 | 238 | if (part.Length > 1) 239 | { 240 | var index = part.LastIndexOfAny(_punctuations); 241 | if (index > -1) 242 | { 243 | if (index == part.Length - 1) 244 | { 245 | if (Resolve(part[index].ToString()) != 0) break; 246 | else throw new NotImplementedException(); 247 | } 248 | else 249 | { 250 | i += index + 1; 251 | continue; 252 | } 253 | } 254 | } 255 | 256 | var _matchLength = Resolve(part); 257 | if (_matchLength != 0) 258 | { 259 | matchLength = _matchLength; 260 | break; 261 | } 262 | else i++; 263 | } 264 | } 265 | 266 | return [.. list]; 267 | } 268 | 269 | /// 270 | /// 转换指定字符串到繁体中文。 271 | /// 272 | /// 273 | /// 274 | public string ToTraditional(string chinese) 275 | { 276 | var words = SplitWords(chinese, ChineseType.Simplified); 277 | var sb = new StringBuilder(chinese.Length * 2); 278 | 279 | foreach (var word in words) 280 | { 281 | sb.Append(word?.Traditional); 282 | } 283 | return sb.ToString(); 284 | } 285 | 286 | /// 287 | /// 转换指定字符串到简体中文。 288 | /// 289 | /// 290 | /// 291 | public string ToSimplified(string chinese) 292 | { 293 | var words = SplitWords(chinese, ChineseType.Traditional); 294 | var sb = new StringBuilder(chinese.Length * 2); 295 | 296 | foreach (var word in words) 297 | { 298 | sb.Append(word?.Simplified); 299 | } 300 | return sb.ToString(); 301 | } 302 | 303 | /// 304 | /// 获取拼音(简体中文) 305 | /// 306 | /// 307 | /// 308 | /// 309 | public string GetPinyin(string chinese, PinyinFormat format = PinyinFormat.Default) 310 | { 311 | return GetPinyin(chinese, ChineseType.Simplified, format); 312 | } 313 | 314 | /// 315 | /// 获取指定类型字符串的拼音 316 | /// 317 | /// 318 | /// 319 | /// 320 | /// 321 | [Obsolete("Use GetPinyin(string chinese, ChineseType type, PinyinFormat format = PinyinFormat.Default) instead.")] 322 | public string GetPinyin(ChineseType type, string chinese, PinyinFormat format = PinyinFormat.Default) 323 | { 324 | return GetPinyin(chinese, type, format); 325 | } 326 | 327 | /// 328 | /// 获取指定类型字符串的拼音 329 | /// 330 | /// 331 | /// 332 | /// 333 | /// 334 | public string GetPinyin(string chinese, ChineseType type, PinyinFormat format = PinyinFormat.Default) 335 | { 336 | var words = SplitWords(chinese, type); 337 | 338 | if (!chinese.IsNullOrWhiteSpace()) 339 | { 340 | var sb = new StringBuilder(); 341 | var insertSpace = false; 342 | bool? prevLatin = null; 343 | 344 | foreach (var word in words) 345 | { 346 | var latin = false; 347 | var str = word.GetString(type); 348 | if (str?.Length == 1) 349 | { 350 | var ch = str.ToCharArray()[0]; 351 | if ((int)ch is >= 0x21 and <= 0x7E) 352 | { 353 | latin = true; 354 | } 355 | } 356 | 357 | var pinyin = word.GetPinyin(type); 358 | 359 | if (pinyin is not null) 360 | { 361 | if ((prevLatin == true) || (insertSpace && format != PinyinFormat.InitialConsonant)) 362 | { 363 | sb.Append(' '); 364 | } 365 | 366 | switch (format) 367 | { 368 | case PinyinFormat.Default: sb.Append(pinyin); break; 369 | case PinyinFormat.WithoutTone: sb.Append(GetPinyinWithoutTone(pinyin)); break; 370 | case PinyinFormat.Phonetic: sb.Append(GetPhoneticSymbol(pinyin)); break; 371 | case PinyinFormat.InitialConsonant: sb.Append(GetPinyinInitialConsonant(pinyin)); break; 372 | } 373 | insertSpace = true; 374 | prevLatin = false; 375 | } 376 | else 377 | { 378 | if (prevLatin.HasValue && !prevLatin.Value && latin) 379 | { 380 | sb.Append(' '); 381 | } 382 | 383 | sb.Append(word.GetString(type)); 384 | insertSpace = false; 385 | prevLatin = latin; 386 | } 387 | } 388 | 389 | return sb.ToString(); 390 | } 391 | return chinese; 392 | } 393 | 394 | private readonly static char[] one_to_five = ['1', '2', '3', '4', '5']; 395 | 396 | internal static string? GetPinyinInitialConsonant(string pinyin) 397 | { 398 | var parts = pinyin.Split(' '); 399 | var sb = new StringBuilder(parts.Length); 400 | foreach (var part in parts) 401 | { 402 | sb.Append(part[0]); 403 | } 404 | return sb.ToString(); 405 | } 406 | internal static string? GetPinyinWithoutTone(string pinyin) 407 | { 408 | var sb = new StringBuilder(pinyin.Length); 409 | foreach (var ch in pinyin) 410 | { 411 | if (!one_to_five.Contains(ch)) sb.Append(ch); 412 | } 413 | return sb.ToString(); 414 | } 415 | internal static string? GetPhoneticSymbol(string pinyin) 416 | { 417 | var parts = pinyin.Split(' ').Select(part => 418 | { 419 | if (part.Length == 1) return part; 420 | 421 | var _pinyin = part.Slice(0, -1); 422 | var tone = part[^1]; 423 | 424 | string yunmu; 425 | 426 | if (part.Contains("v")) yunmu = "v"; 427 | else if (part.Contains("iu")) yunmu = "u"; 428 | else if (part.Contains("ui")) yunmu = "i"; 429 | else if (part.Contains("a")) yunmu = "a"; 430 | else if (part.Contains("o")) yunmu = "o"; 431 | else if (part.Contains("e")) yunmu = "e"; 432 | else if (part.Contains("i")) yunmu = "i"; 433 | else if (part.Contains("u")) yunmu = "u"; 434 | else throw new InvalidCastException("Not a Pinyin."); 435 | 436 | var _yunmu = yunmu switch 437 | { 438 | "a" => tone switch { '1' => "ā", '2' => "á", '3' => "ǎ", '4' => "à", _ => "a" }, 439 | "o" => tone switch { '1' => "ō", '2' => "ó", '3' => "ǒ", '4' => "ò", _ => "o" }, 440 | "e" => tone switch { '1' => "ē", '2' => "é", '3' => "ě", '4' => "è", _ => "e" }, 441 | "i" => tone switch { '1' => "ī", '2' => "í", '3' => "ǐ", '4' => "ì", _ => "i" }, 442 | "u" => tone switch { '1' => "ū", '2' => "ú", '3' => "ǔ", '4' => "ù", _ => "u" }, 443 | "v" => tone switch { '1' => "ǖ", '2' => "ǘ", '3' => "ǚ", '4' => "ǜ", _ => "ü" }, 444 | _ => throw new NotImplementedException(), 445 | }; 446 | 447 | return _pinyin.Replace(yunmu, _yunmu); 448 | }); 449 | 450 | return parts.Join(" "); 451 | } 452 | 453 | } 454 | -------------------------------------------------------------------------------- /Chinese/Lexicons/Builtin.cs: -------------------------------------------------------------------------------- 1 | namespace Chinese.Lexicons; 2 | 3 | public static class Builtin 4 | { 5 | public static readonly IWord[] NumericalWords = 6 | [ 7 | new ChineseWord { Simplified = "壹", SimplifiedPinyin = "yi1", Traditional = "壹", TraditionalPinyin = "yi1", Tag = 1 }, 8 | new ChineseWord { Simplified = "贰", SimplifiedPinyin = "er4", Traditional = "貳", TraditionalPinyin = "er4", Tag = 2 }, 9 | new ChineseWord { Simplified = "叁", SimplifiedPinyin = "san1", Traditional = "叁", TraditionalPinyin = "san1", Tag = 3 }, 10 | new ChineseWord { Simplified = "肆", SimplifiedPinyin = "si4", Traditional = "肆", TraditionalPinyin = "si4", Tag = 4 }, 11 | new ChineseWord { Simplified = "伍", SimplifiedPinyin = "wu3", Traditional = "伍", TraditionalPinyin = "wu3", Tag = 5 }, 12 | new ChineseWord { Simplified = "陆", SimplifiedPinyin = "lu4", Traditional = "陸", TraditionalPinyin = "lu4", Tag = 6 }, 13 | new ChineseWord { Simplified = "柒", SimplifiedPinyin = "qi1", Traditional = "柒", TraditionalPinyin = "qi1", Tag = 7 }, 14 | new ChineseWord { Simplified = "捌", SimplifiedPinyin = "ba1", Traditional = "捌", TraditionalPinyin = "ba1", Tag = 8 }, 15 | new ChineseWord { Simplified = "玖", SimplifiedPinyin = "jiu3", Traditional = "玖", TraditionalPinyin = "jiu3", Tag = 9 }, 16 | new ChineseWord { Simplified = "壹拾", SimplifiedPinyin = "yi1 shi2", Traditional = "壹拾", TraditionalPinyin = "yi1 shi2", Tag = 10 }, 17 | new ChineseWord { Simplified = "贰拾", SimplifiedPinyin = "er4 shi2", Traditional = "貳拾", TraditionalPinyin = "er4 shi2", Tag = 20 }, 18 | new ChineseWord { Simplified = "叁拾", SimplifiedPinyin = "san1 shi2", Traditional = "叁拾", TraditionalPinyin = "san1 shi2", Tag = 30 }, 19 | new ChineseWord { Simplified = "肆拾", SimplifiedPinyin = "si4 shi2", Traditional = "肆拾", TraditionalPinyin = "si4 shi2", Tag = 40 }, 20 | new ChineseWord { Simplified = "伍拾", SimplifiedPinyin = "wu3 shi2", Traditional = "伍拾", TraditionalPinyin = "wu3 shi2", Tag = 50 }, 21 | new ChineseWord { Simplified = "陆拾", SimplifiedPinyin = "lu4 shi2", Traditional = "陸拾", TraditionalPinyin = "lu4 shi2", Tag = 60 }, 22 | new ChineseWord { Simplified = "柒拾", SimplifiedPinyin = "qi1 shi2", Traditional = "柒拾", TraditionalPinyin = "qi1 shi2", Tag = 70 }, 23 | new ChineseWord { Simplified = "捌拾", SimplifiedPinyin = "ba1 shi2", Traditional = "捌拾", TraditionalPinyin = "ba1 shi2", Tag = 80 }, 24 | new ChineseWord { Simplified = "玖拾", SimplifiedPinyin = "jiu3 shi2", Traditional = "玖拾", TraditionalPinyin = "jiu3 shi2", Tag = 90 }, 25 | new ChineseWord { Simplified = "壹佰", SimplifiedPinyin = "yi1 bai3", Traditional = "壹佰", TraditionalPinyin = "yi1 bai3", Tag = 100 }, 26 | new ChineseWord { Simplified = "贰佰", SimplifiedPinyin = "er4 bai3", Traditional = "貳佰", TraditionalPinyin = "er4 bai3", Tag = 200 }, 27 | new ChineseWord { Simplified = "叁佰", SimplifiedPinyin = "san1 bai3", Traditional = "叁佰", TraditionalPinyin = "san1 bai3", Tag = 300 }, 28 | new ChineseWord { Simplified = "肆佰", SimplifiedPinyin = "si4 bai3", Traditional = "肆佰", TraditionalPinyin = "si4 bai3", Tag = 400 }, 29 | new ChineseWord { Simplified = "伍佰", SimplifiedPinyin = "wu3 bai3", Traditional = "伍佰", TraditionalPinyin = "wu3 bai3", Tag = 500 }, 30 | new ChineseWord { Simplified = "陆佰", SimplifiedPinyin = "lu4 bai3", Traditional = "陸佰", TraditionalPinyin = "lu4 bai3", Tag = 600 }, 31 | new ChineseWord { Simplified = "柒佰", SimplifiedPinyin = "qi1 bai3", Traditional = "柒佰", TraditionalPinyin = "qi1 bai3", Tag = 700 }, 32 | new ChineseWord { Simplified = "捌佰", SimplifiedPinyin = "ba1 bai3", Traditional = "捌佰", TraditionalPinyin = "ba1 bai3", Tag = 800 }, 33 | new ChineseWord { Simplified = "玖佰", SimplifiedPinyin = "jiu3 bai3", Traditional = "玖佰", TraditionalPinyin = "jiu3 bai3", Tag = 900 }, 34 | new ChineseWord { Simplified = "壹仟", SimplifiedPinyin = "yi1 qian1", Traditional = "壹仟", TraditionalPinyin = "yi1 qian1", Tag = 1000 }, 35 | new ChineseWord { Simplified = "贰仟", SimplifiedPinyin = "er4 qian1", Traditional = "貳仟", TraditionalPinyin = "er4 qian1", Tag = 2000 }, 36 | new ChineseWord { Simplified = "叁仟", SimplifiedPinyin = "san1 qian1", Traditional = "叁仟", TraditionalPinyin = "san1 qian1", Tag = 3000 }, 37 | new ChineseWord { Simplified = "肆仟", SimplifiedPinyin = "si4 qian1", Traditional = "肆仟", TraditionalPinyin = "si4 qian1", Tag = 4000 }, 38 | new ChineseWord { Simplified = "伍仟", SimplifiedPinyin = "wu3 qian1", Traditional = "伍仟", TraditionalPinyin = "wu3 qian1", Tag = 5000 }, 39 | new ChineseWord { Simplified = "陆仟", SimplifiedPinyin = "lu4 qian1", Traditional = "陸仟", TraditionalPinyin = "lu4 qian1", Tag = 6000 }, 40 | new ChineseWord { Simplified = "柒仟", SimplifiedPinyin = "qi1 qian1", Traditional = "柒仟", TraditionalPinyin = "qi1 qian1", Tag = 7000 }, 41 | new ChineseWord { Simplified = "捌仟", SimplifiedPinyin = "ba1 qian1", Traditional = "捌仟", TraditionalPinyin = "ba1 qian1", Tag = 8000 }, 42 | new ChineseWord { Simplified = "玖仟", SimplifiedPinyin = "jiu3 qian1", Traditional = "玖仟", TraditionalPinyin = "jiu3 qian1", Tag = 9000 }, 43 | new ChineseWord { Simplified = "一", SimplifiedPinyin = "yi1", Traditional = "一", TraditionalPinyin = "yi1", Tag = 1 }, 44 | new ChineseWord { Simplified = "二", SimplifiedPinyin = "er4", Traditional = "二", TraditionalPinyin = "er4", Tag = 2 }, 45 | new ChineseWord { Simplified = "三", SimplifiedPinyin = "san1", Traditional = "三", TraditionalPinyin = "san1", Tag = 3 }, 46 | new ChineseWord { Simplified = "四", SimplifiedPinyin = "si4", Traditional = "四", TraditionalPinyin = "si4", Tag = 4 }, 47 | new ChineseWord { Simplified = "五", SimplifiedPinyin = "wu3", Traditional = "五", TraditionalPinyin = "wu3", Tag = 5 }, 48 | new ChineseWord { Simplified = "六", SimplifiedPinyin = "liu4", Traditional = "六", TraditionalPinyin = "liu4", Tag = 6 }, 49 | new ChineseWord { Simplified = "七", SimplifiedPinyin = "qi1", Traditional = "七", TraditionalPinyin = "qi1", Tag = 7 }, 50 | new ChineseWord { Simplified = "八", SimplifiedPinyin = "ba1", Traditional = "八", TraditionalPinyin = "ba1", Tag = 8 }, 51 | new ChineseWord { Simplified = "九", SimplifiedPinyin = "jiu3", Traditional = "九", TraditionalPinyin = "jiu3", Tag = 9 }, 52 | new ChineseWord { Simplified = "一十", SimplifiedPinyin = "yi1 shi2", Traditional = "一十", TraditionalPinyin = "yi1 shi2", Tag = 10 }, 53 | new ChineseWord { Simplified = "二十", SimplifiedPinyin = "er4 shi2", Traditional = "二十", TraditionalPinyin = "er4 shi2", Tag = 20 }, 54 | new ChineseWord { Simplified = "三十", SimplifiedPinyin = "san1 shi2", Traditional = "三十", TraditionalPinyin = "san1 shi2", Tag = 30 }, 55 | new ChineseWord { Simplified = "四十", SimplifiedPinyin = "si4 shi2", Traditional = "四十", TraditionalPinyin = "si4 shi2", Tag = 40 }, 56 | new ChineseWord { Simplified = "五十", SimplifiedPinyin = "wu3 shi2", Traditional = "五十", TraditionalPinyin = "wu3 shi2", Tag = 50 }, 57 | new ChineseWord { Simplified = "六十", SimplifiedPinyin = "liu4 shi2", Traditional = "六十", TraditionalPinyin = "liu4 shi2", Tag = 60 }, 58 | new ChineseWord { Simplified = "七十", SimplifiedPinyin = "qi1 shi2", Traditional = "七十", TraditionalPinyin = "qi1 shi2", Tag = 70 }, 59 | new ChineseWord { Simplified = "八十", SimplifiedPinyin = "ba1 shi2", Traditional = "八十", TraditionalPinyin = "ba1 shi2", Tag = 80 }, 60 | new ChineseWord { Simplified = "九十", SimplifiedPinyin = "jiu3 shi2", Traditional = "九十", TraditionalPinyin = "jiu3 shi2", Tag = 90 }, 61 | new ChineseWord { Simplified = "一百", SimplifiedPinyin = "yi1 bai3", Traditional = "一百", TraditionalPinyin = "yi1 bai3", Tag = 100 }, 62 | new ChineseWord { Simplified = "二百", SimplifiedPinyin = "er4 bai3", Traditional = "二百", TraditionalPinyin = "er4 bai3", Tag = 200 }, 63 | new ChineseWord { Simplified = "三百", SimplifiedPinyin = "san1 bai3", Traditional = "三百", TraditionalPinyin = "san1 bai3", Tag = 300 }, 64 | new ChineseWord { Simplified = "四百", SimplifiedPinyin = "si4 bai3", Traditional = "四百", TraditionalPinyin = "si4 bai3", Tag = 400 }, 65 | new ChineseWord { Simplified = "五百", SimplifiedPinyin = "wu3 bai3", Traditional = "五百", TraditionalPinyin = "wu3 bai3", Tag = 500 }, 66 | new ChineseWord { Simplified = "六百", SimplifiedPinyin = "liu4 bai3", Traditional = "六百", TraditionalPinyin = "liu4 bai3", Tag = 600 }, 67 | new ChineseWord { Simplified = "七百", SimplifiedPinyin = "qi1 bai3", Traditional = "七百", TraditionalPinyin = "qi1 bai3", Tag = 700 }, 68 | new ChineseWord { Simplified = "八百", SimplifiedPinyin = "ba1 bai3", Traditional = "八百", TraditionalPinyin = "ba1 bai3", Tag = 800 }, 69 | new ChineseWord { Simplified = "九百", SimplifiedPinyin = "jiu3 bai3", Traditional = "九百", TraditionalPinyin = "jiu3 bai3", Tag = 900 }, 70 | new ChineseWord { Simplified = "一千", SimplifiedPinyin = "yi1 qian1", Traditional = "一千", TraditionalPinyin = "yi1 qian1", Tag = 1000 }, 71 | new ChineseWord { Simplified = "二千", SimplifiedPinyin = "er4 qian1", Traditional = "二千", TraditionalPinyin = "er4 qian1", Tag = 2000 }, 72 | new ChineseWord { Simplified = "三千", SimplifiedPinyin = "san1 qian1", Traditional = "三千", TraditionalPinyin = "san1 qian1", Tag = 3000 }, 73 | new ChineseWord { Simplified = "四千", SimplifiedPinyin = "si4 qian1", Traditional = "四千", TraditionalPinyin = "si4 qian1", Tag = 4000 }, 74 | new ChineseWord { Simplified = "五千", SimplifiedPinyin = "wu3 qian1", Traditional = "五千", TraditionalPinyin = "wu3 qian1", Tag = 5000 }, 75 | new ChineseWord { Simplified = "六千", SimplifiedPinyin = "liu4 qian1", Traditional = "六千", TraditionalPinyin = "liu4 qian1", Tag = 6000 }, 76 | new ChineseWord { Simplified = "七千", SimplifiedPinyin = "qi1 qian1", Traditional = "七千", TraditionalPinyin = "qi1 qian1", Tag = 7000 }, 77 | new ChineseWord { Simplified = "八千", SimplifiedPinyin = "ba1 qian1", Traditional = "八千", TraditionalPinyin = "ba1 qian1", Tag = 8000 }, 78 | new ChineseWord { Simplified = "九千", SimplifiedPinyin = "jiu3 qian1", Traditional = "九千", TraditionalPinyin = "jiu3 qian1", Tag = 9000 }, 79 | new ChineseWord { Simplified = "两", SimplifiedPinyin = "liang3", Traditional = "两", TraditionalPinyin = "liang3", Tag = 2 }, 80 | new ChineseWord { Simplified = "两百", SimplifiedPinyin = "liang3 bai3", Traditional = "两百", TraditionalPinyin = "liang3 bai3", Tag = 200 }, 81 | new ChineseWord { Simplified = "两千", SimplifiedPinyin = "liang3 qian1", Traditional = "两千", TraditionalPinyin = "liang3 qian1", Tag = 2000 }, 82 | 83 | new ChineseWord { Simplified = "〇", SimplifiedPinyin = "ling2", Traditional = "〇", TraditionalPinyin = "ling2", Tag = 0 }, 84 | 85 | new ChineseWord { Simplified = "十", SimplifiedPinyin = "shi2", Traditional = "十", TraditionalPinyin = "shi2", Tag = null }, 86 | new ChineseWord { Simplified = "百", SimplifiedPinyin = "bai3", Traditional = "百", TraditionalPinyin = "bai3", Tag = null }, 87 | new ChineseWord { Simplified = "千", SimplifiedPinyin = "qian1", Traditional = "千", TraditionalPinyin = "qian1", Tag = null }, 88 | new ChineseWord { Simplified = "拾", SimplifiedPinyin = "shi2", Traditional = "拾", TraditionalPinyin = "shi2", Tag = null }, 89 | new ChineseWord { Simplified = "佰", SimplifiedPinyin = "bai3", Traditional = "佰", TraditionalPinyin = "bai3", Tag = null }, 90 | new ChineseWord { Simplified = "仟", SimplifiedPinyin = "qian1", Traditional = "仟", TraditionalPinyin = "qian1", Tag = null }, 91 | 92 | new ChineseWord { Simplified = "万", SimplifiedPinyin = "wan4", Traditional = "萬", TraditionalPinyin = "wan4", Tag = null }, 93 | new ChineseWord { Simplified = "亿", SimplifiedPinyin = "yi4", Traditional = "億", TraditionalPinyin = "yi4", Tag = null }, 94 | 95 | new ChineseWord { Simplified = "兆", SimplifiedPinyin = "zhao4", Traditional = "兆", TraditionalPinyin = "zhao4", Tag = null }, 96 | new ChineseWord { Simplified = "京", SimplifiedPinyin = "jing1", Traditional = "京", TraditionalPinyin = "jing1", Tag = null }, 97 | new ChineseWord { Simplified = "垓", SimplifiedPinyin = "gai1", Traditional = "垓", TraditionalPinyin = "gai1", Tag = null }, 98 | new ChineseWord { Simplified = "秭", SimplifiedPinyin = "zi3", Traditional = "秭", TraditionalPinyin = "zi3", Tag = null }, 99 | new ChineseWord { Simplified = "穰", SimplifiedPinyin = "rang2", Traditional = "穰", TraditionalPinyin = "rang2", Tag = null }, 100 | 101 | new ChineseWord { Simplified = "万亿", SimplifiedPinyin = "wan4 yi4", Traditional = "萬億", TraditionalPinyin = "wan4 yi4", Tag = null }, 102 | new ChineseWord { Simplified = "亿亿", SimplifiedPinyin = "yi4 yi4", Traditional = "億億", TraditionalPinyin = "yi4 yi4", Tag = null }, 103 | new ChineseWord { Simplified = "万亿亿", SimplifiedPinyin = "wan4 yi4 yi4", Traditional = "萬億億", TraditionalPinyin = "wan4 yi4 yi4", Tag = null }, 104 | new ChineseWord { Simplified = "亿亿亿", SimplifiedPinyin = "yi4 yi4 yi4", Traditional = "億億億", TraditionalPinyin = "yi4 yi4 yi4", Tag = null }, 105 | new ChineseWord { Simplified = "万亿亿亿", SimplifiedPinyin = "wan4 yi4 yi4 yi4", Traditional = "萬億億億", TraditionalPinyin = "wan4 yi4 yi4 yi4", Tag = null }, 106 | 107 | new ChineseWord { Simplified = "元", SimplifiedPinyin = "yuan2", Traditional = "元", TraditionalPinyin = "yuan2", Tag = null }, 108 | new ChineseWord { Simplified = "圆", SimplifiedPinyin = "yuan2", Traditional = "圓", TraditionalPinyin = "yuan2", Tag = null }, 109 | new ChineseWord { Simplified = "角", SimplifiedPinyin = "jiao3", Traditional = "角", TraditionalPinyin = "jiao3", Tag = null }, 110 | new ChineseWord { Simplified = "分", SimplifiedPinyin = "fen1", Traditional = "分", TraditionalPinyin = "fen1", Tag = null }, 111 | ]; 112 | } 113 | -------------------------------------------------------------------------------- /Chinese/Lexicons/CurrencyLexicon.cs: -------------------------------------------------------------------------------- 1 | using NStandard; 2 | using System; 3 | using System.Text.RegularExpressions; 4 | 5 | namespace Chinese.Lexicons; 6 | 7 | public class CurrencyLexicon : Lexicon 8 | { 9 | private readonly NumberLexicon _numericLexicon; 10 | 11 | private readonly Regex _currencyRegex; 12 | private readonly string[] _levels; 13 | 14 | public CurrencyLexicon(NumberMode mode) 15 | { 16 | _numericLexicon = new(mode); 17 | 18 | if (mode.HasFlag(NumberMode.Upper)) 19 | { 20 | _levels = ["圆", "角", "分"]; 21 | _currencyRegex = new Regex(@"^(.+)(?:圆)(?:整|(.)角整|(.)角(.)分|零(.)分)$", RegexOptions.Compiled); 22 | } 23 | else 24 | { 25 | _levels = ["元", "角", "分"]; 26 | _currencyRegex = new Regex(@"^(.+)(?:元)(?:整|(.)角整|(.)角(.)分|零(.)分)$", RegexOptions.Compiled); 27 | } 28 | } 29 | 30 | /// 31 | /// 获取数值的货币读法。 32 | /// 33 | /// 34 | /// 35 | /// 36 | public string GetString(decimal currency) 37 | { 38 | var fractional100 = (int)(currency % 1 * 100 % 100); 39 | 40 | var yuan = $"{_numericLexicon.GetString(currency)}{_levels[0]}"; 41 | if (fractional100 == 0) 42 | { 43 | return $"{yuan}整"; 44 | } 45 | else if (fractional100 % 10 == 0) 46 | { 47 | var jiao = $"{_numericLexicon.GetString(fractional100 / 10)}{_levels[1]}"; 48 | return $"{yuan}{jiao}整"; 49 | } 50 | else 51 | { 52 | var jiao_value = fractional100 / 10; 53 | var jiao = jiao_value > 0 54 | ? $"{_numericLexicon.GetString(fractional100 / 10)}{_levels[1]}" 55 | : "零"; 56 | 57 | var fen = $"{_numericLexicon.GetString(fractional100 % 10)}{_levels[2]}"; 58 | return $"{yuan}{jiao}{fen}"; 59 | } 60 | } 61 | 62 | /// 63 | /// 获取货币读法的数值。 64 | /// 65 | /// 66 | /// 67 | public decimal GetNumber(string currency) 68 | { 69 | var match = _currencyRegex.Match(currency); 70 | 71 | if (!match.Success) throw new ArgumentException("不是合法的中文货币描述。", nameof(currency)); 72 | 73 | var yuan = _numericLexicon.GetNumber(match.Groups[1].Value); 74 | 75 | var jiao_value = match.Groups[2].Value; 76 | if (jiao_value.IsWhiteSpace()) jiao_value = match.Groups[3].Value; 77 | var jiao = jiao_value.IsWhiteSpace() ? 0m : _numericLexicon.GetNumber(jiao_value); 78 | 79 | var fen_value = match.Groups[4].Value; 80 | if (fen_value.IsWhiteSpace()) fen_value = match.Groups[5].Value; 81 | var fen = fen_value.IsWhiteSpace() ? 0m : _numericLexicon.GetNumber(fen_value); 82 | 83 | return yuan + jiao * 0.1m + fen * 0.01m; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Chinese/Lexicons/NumberLexicon.cs: -------------------------------------------------------------------------------- 1 | using NStandard; 2 | using System; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Chinese.Lexicons; 7 | 8 | public class NumberLexicon : Lexicon 9 | { 10 | private const int PART_COUNT = 4; 11 | private const int SUPPORTED_SEPARATOR_COUNT = 8; 12 | private string[] _separators; 13 | /// 14 | /// 数值分级单位 15 | /// 16 | public string[] Separators 17 | { 18 | get => _separators; 19 | set 20 | { 21 | if (value.Length > SUPPORTED_SEPARATOR_COUNT) throw new NotSupportedException($"超过最大支持分隔符数量({SUPPORTED_SEPARATOR_COUNT})。"); 22 | _separators = value; 23 | } 24 | } 25 | public bool Code { get; set; } 26 | public bool Concise { get; set; } 27 | public ChineseType ChineseType { get; set; } 28 | 29 | private readonly string[] _values; 30 | private readonly string[] _levels; 31 | 32 | public NumberLexicon(NumberMode mode) 33 | { 34 | Add(Builtin.NumericalWords); 35 | 36 | Code = mode.HasFlag(NumberMode.Code); 37 | Concise = mode.HasFlag(NumberMode.Concise); 38 | ChineseType = mode.HasFlag(NumberMode.Traditional) ? ChineseType.Traditional : ChineseType.Simplified; 39 | 40 | if (mode.HasFlag(NumberMode.Classical)) 41 | { 42 | Separators = [string.Empty, "万", "亿", "兆", "京", "垓", "秭", "穰"]; 43 | } 44 | else 45 | { 46 | Separators = [string.Empty, "万", "亿", "万亿", "亿亿", "万亿亿", "亿亿亿", "万亿亿亿"]; 47 | } 48 | 49 | if (mode.HasFlag(NumberMode.Upper)) 50 | { 51 | _levels = [string.Empty, "拾", "佰", "仟"]; 52 | _values = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"]; 53 | } 54 | else 55 | { 56 | _levels = [string.Empty, "十", "百", "千"]; 57 | _values = 58 | [ 59 | mode.HasFlag(NumberMode.Code) ? "〇" : "零", 60 | "一", "二", "三", "四", "五", "六", "七", "八", "九" 61 | ]; 62 | } 63 | } 64 | 65 | /// 66 | /// 获取数字的编号读法。 67 | /// 68 | /// 69 | /// 70 | private string GetCodeString(decimal number) 71 | { 72 | var s_number = number.ToString(); 73 | if (!s_number.All(ch => '0' <= ch && ch <= '9')) throw new ArgumentException("不是合法的数字编号。"); 74 | 75 | var sb = new StringBuilder(s_number.Length + 1); 76 | foreach (var ch in s_number) sb.Append(_values[ch - '0']); 77 | 78 | return sb.ToString(); 79 | } 80 | 81 | /// 82 | /// 获取数字的编号读法。 83 | /// 84 | /// 85 | /// 86 | private decimal GetCodeNumber(string number) 87 | { 88 | var sb = new StringBuilder(number.Length + 1); 89 | foreach (var ch in number) 90 | { 91 | var value = _values.IndexOf(ch.ToString()); 92 | 93 | if (value > -1) sb.Append(value); 94 | else throw new ArgumentException("不是合法的中文数字编号描述。", nameof(number)); 95 | } 96 | 97 | return decimal.Parse(sb.ToString()); 98 | } 99 | 100 | /// 101 | /// 获取数值的数值读法。 102 | /// 103 | /// 104 | /// 105 | public string GetString(decimal number) 106 | { 107 | if (Code) return GetCodeString(number); 108 | 109 | number = number switch 110 | { 111 | 0 => number, 112 | > 0 => decimal.Floor(number), 113 | < 0 => decimal.Ceiling(number), 114 | }; 115 | 116 | string GetPartString(char[] singles, string level, bool prevZero) 117 | { 118 | if (!singles.Any()) return string.Empty; 119 | 120 | var sb = new StringBuilder(); 121 | var zero = prevZero; 122 | foreach (var (index, single) in singles.Pairs()) 123 | { 124 | if (single != '0') 125 | { 126 | var value = _values[single - '0']; 127 | var unit = _levels[singles.Length - 1 - index]; 128 | 129 | if (zero) sb.Append(_values[0]); 130 | sb.Append($"{value}{unit}"); 131 | 132 | zero = false; 133 | } 134 | else 135 | { 136 | zero = true; 137 | } 138 | } 139 | 140 | if (sb.Length == 0) return null; 141 | else 142 | { 143 | sb.Append(level); 144 | return sb.ToString(); 145 | } 146 | } 147 | 148 | var s_number = number.ToString(); 149 | var enumerator_s_number = s_number.GetEnumerator(); 150 | 151 | var levelParts = new char[(s_number.Length - 1) / 4 + 1][]; 152 | var enumerator_levelParts = levelParts.GetEnumerator(); 153 | if (enumerator_levelParts.MoveNext()) 154 | { 155 | var mod = s_number.Length % PART_COUNT; 156 | levelParts[0] = new char[mod > 0 ? mod : 4]; 157 | for (int j = 0; j < levelParts[0].Length; j++) 158 | { 159 | enumerator_s_number.MoveNext(); 160 | levelParts[0][j] = enumerator_s_number.Current; 161 | } 162 | 163 | int i = 1; 164 | while (enumerator_levelParts.MoveNext()) 165 | { 166 | levelParts[i] = new char[4]; 167 | for (int j = 0; j < PART_COUNT; j++) 168 | { 169 | enumerator_s_number.MoveNext(); 170 | levelParts[i][j] = enumerator_s_number.Current; 171 | } 172 | i++; 173 | } 174 | } 175 | 176 | var sb = new StringBuilder(); 177 | int part_i = 0; 178 | bool prevZero = false; 179 | foreach (var part in levelParts) 180 | { 181 | var partString = GetPartString(part, Separators[levelParts.Length - 1 - part_i], prevZero); 182 | if (partString is not null) 183 | { 184 | sb.Append(partString); 185 | prevZero = false; 186 | } 187 | else prevZero = true; 188 | part_i++; 189 | } 190 | 191 | if (sb.Length == 0) return _values[0]; 192 | 193 | if (Concise && sb.Length > 1) 194 | { 195 | if (sb[0] == '一' && sb[1] == '十' || sb[0] == '壹' && sb[1] == '拾') 196 | { 197 | sb.Remove(0, 1); 198 | } 199 | } 200 | 201 | return sb.ToString(); 202 | } 203 | 204 | /// 205 | /// 获取数值读法的数值。 206 | /// 207 | /// 208 | /// 209 | public decimal GetNumber(string number) 210 | { 211 | if (Code) return GetCodeNumber(number); 212 | 213 | if (number.Length == 0) return default; 214 | 215 | var last = number.Last(); 216 | if (last == '两') throw new ArgumentException($"不能以该字结尾:{last}", nameof(number)); 217 | 218 | var words = SplitWords(number, ChineseType); 219 | var total = 0m; 220 | var levelNumber = 0; 221 | foreach (var word in words) 222 | { 223 | var ch = word.Simplified; 224 | 225 | if (ch == "零") continue; 226 | else if (ch == "十" || ch == "拾") levelNumber += 10; 227 | else 228 | { 229 | if (word.Tag is int @int) 230 | { 231 | levelNumber += @int; 232 | } 233 | else 234 | { 235 | var level = _separators.IndexOf(ch); 236 | if (level > -1) 237 | { 238 | total += levelNumber * level switch 239 | { 240 | 1 => 1_0000, 241 | 2 => 1_0000_0000, 242 | 3 => 1_0000_0000_0000, 243 | 4 => 1_0000_0000_0000_0000, 244 | 5 => 1_0000_0000_0000_0000_0000m, 245 | 6 => 1_0000_0000_0000_0000_0000_0000m, 246 | 7 => 1_0000_0000_0000_0000_0000_0000_0000m, 247 | _ => throw new NotImplementedException(), 248 | }; 249 | levelNumber = 0; 250 | } 251 | else throw new ArgumentException($"不能解析的词汇:{word}", nameof(number)); 252 | } 253 | } 254 | } 255 | total += levelNumber; 256 | return total; 257 | } 258 | 259 | } 260 | -------------------------------------------------------------------------------- /Chinese/Lexicons/NumberMode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Chinese.Lexicons; 4 | 5 | [Flags] 6 | public enum NumberMode 7 | { 8 | Default = 0, 9 | 10 | Traditional = 0b0010, 11 | Classical = 0b0100, 12 | Concise = 0b1000, 13 | 14 | Upper = 0b1_00000000, 15 | Code = 0b10_00000000, 16 | } 17 | -------------------------------------------------------------------------------- /ChineseApp/ChineseApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /ChineseApp/Program.cs: -------------------------------------------------------------------------------- 1 | using Chinese; 2 | using Chinese.Data; 3 | using Chinese.Lexicons; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Logging; 6 | using System.Diagnostics; 7 | 8 | namespace ChineseApp; 9 | 10 | internal class Program 11 | { 12 | public class MySqlLexicon : Lexicon 13 | { 14 | public static MySqlLexicon UseDefault() 15 | { 16 | var mysqlConnectionString = "server=127.0.0.1;port=33306;user=root;password=root;database=chinese"; 17 | var mysqlOptions = new DbContextOptionsBuilder() 18 | .UseMySql(mysqlConnectionString, ServerVersion.AutoDetect(mysqlConnectionString), null) 19 | .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())).Options; 20 | 21 | var context = new ChineseDbContext(mysqlOptions); 22 | return new MySqlLexicon(context); 23 | } 24 | 25 | public MySqlLexicon(ChineseDbContext context) 26 | { 27 | Add(context.Words); 28 | Add(context.Chars); 29 | } 30 | } 31 | 32 | static void Main(string[] args) 33 | { 34 | var watch = new Stopwatch(); 35 | 36 | //var lexicon = MySqlLexicon.UseDefault(); 37 | //Console.WriteLine(lexicon.GetPinyin("只有这只鸟跑得很快。")); 38 | 39 | { 40 | var lexicon = Lexicon.Currency; 41 | Console.WriteLine( 42 | Lexicon.Currency.GetString(0.1m) 43 | ); 44 | } 45 | 46 | { 47 | watch.Restart(); 48 | var currency = Lexicon.Currency; 49 | for (int i = 0; i < 100; i++) 50 | { 51 | var result = currency.GetNumber("一百二十三亿亿亿四千五百六十七万亿亿八千九百零一亿亿二千三百四十五万亿六千七百八十九亿零一百二十三万四千五百六十七元八角九分"); 52 | if (i == 0) Console.WriteLine(result); 53 | } 54 | watch.Stop(); 55 | Console.WriteLine(watch.Elapsed); 56 | 57 | watch.Restart(); 58 | for (int i = 0; i < 100; i++) 59 | { 60 | var result = currency.GetString(123456789012345678901234567.89M); 61 | if (i == 0) Console.WriteLine(result); 62 | } 63 | watch.Stop(); 64 | Console.WriteLine(watch.Elapsed); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 zmjack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LexiconBuilder/LexiconBuilder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | true 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /LexiconBuilder/Program.cs: -------------------------------------------------------------------------------- 1 | namespace LexiconBuilder; 2 | 3 | internal class Program 4 | { 5 | static void Main(string[] args) 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chinese 2 | 3 | 中文解析通用工具。包括拼音,简繁转换,数字读法,货币读法。 4 | 5 |
6 | 7 | ## 安装 8 | 9 | 通过 **Nuget** 使用 **.NET CLI** 安装: 10 | 11 | ```powershell 12 | dotnet add package Chinese 13 | ``` 14 | 15 | 16 | 17 | ## 版本更新 18 | 19 | ### 版本:0.8.1-alpha 20 | 21 | 欢迎仅使用 **数字转换** / **货币转换** 功能的项目升级试用。 22 | 23 | - [x] 大量逻辑优化,优化内存使用。 24 | 25 | - [x] 提高 **数字转换** / **货币转换** 性能,修复一些 **BUG**(Issues: #10)。 26 | 27 | ```csharp 28 | Lexicon.Currency.GetString(0.1m); // 零元一角整 29 | ``` 30 | 31 | - [x] 修复 **中文掺杂字母或拼音** 转换时缺少 **空格** 的问题(Issues: #12)。 32 | 33 | - [ ] 数值读法增加 **小数** 读法。 34 | 35 | - [ ] 提供外部词库支持,现可使用 **数据库** 作为外部词库源。(结构需优化) 36 | 37 | - [ ] 词库编译生成器(解析 **文本结构** 到 **Sqlite** 数据库文件,用户可以通过文本结构提交 PR 贡献)。 38 | 39 | ### 版本:0.5.0 40 | 41 | - 简繁转换性能优化(**NETStandard2.0+**,**NET5.0+**,通常情况耗时减少约 **90%**)。 42 | 43 | - 计量读法性能优化(耗时减少约 **85%**)。 44 | 45 | - 修复计量读法尾零转换错误问题: 46 | 47 | ```csharp 48 | var wrong = ChineseCurrency.GetString(10_0000); // 错误:一十万零元整 49 | var right = ChineseCurrency.GetString(10_0000); // 正确:一十万元整 50 | ``` 51 | 52 | ### 版本:4.5.0 53 | 54 | - 更新部分字默认拼音。 55 | - 发布测试词库 **Chinese.Words**(v0.0.1)。 56 | 57 | ### 版本:4.1.0 58 | 59 | - 按词频为单字提供默认拼音。 60 | 61 |
62 | 63 | ## 拼音 64 | 65 | ```c# 66 | // "mian3 fei4,kua4 ping2 tai2,kai1 yuan2!" 67 | Pinyin.GetString("免费,跨平台,开源!", PinyinFormat.Default); 68 | ``` 69 | 70 | ```c# 71 | // "mian fei,kua ping tai,kai yuan!" 72 | Pinyin.GetString("免费,跨平台,开源!", PinyinFormat.WithoutTone); 73 | ``` 74 | 75 | ```c# 76 | // "miǎn fèi,kuà píng tái,kāi yuán!" 77 | Pinyin.GetString("免费,跨平台,开源!", PinyinFormat.Phonetic); 78 | ``` 79 | 80 | ```c# 81 | // "mf,kpt,ky!" 82 | Pinyin.GetString("免费,跨平台,开源!", PinyinFormat.InitialConsonant); 83 | ``` 84 | 85 |
86 | 87 | ## 简繁转换 88 | 89 | ```c# 90 | ChineseConverter.ToTraditional("免费,跨平台,开源!"); // "免費,跨平臺,開源!" 91 | ChineseConverter.ToSimplified("免費,跨平臺,開源!"); // "免费,跨平台,开源!" 92 | ``` 93 | 94 |
95 | 96 | ## 数字读法 97 | 98 | | NumberMode 选项 | 描述 | 示例 | 99 | | --------------- | ------------------------------------------------------------ | ------------------------- | 100 | | **Default** | 流行读法,亿级以上使用 `千亿` `万亿` 等单位;
不省略第一个 `十` 前的 `一` ;
小写读法。 | - | 101 | | **Classical** | 经典读法,亿级以上使用 `兆` `京` 等单位 | - | 102 | | **Concise** | 简洁读法,省略第一个 `十` 前的 `一` | `10_0001` 读作 `十万零一` | 103 | | **Upper** | 大写读法 | `1` 读作 `壹` | 104 | 105 | 106 | 107 | ### 计量读法 108 | 109 | ```c# 110 | var lexicon = Lexicon.Number; 111 | lexicon.GetString(10_0001); // "一十万零一" 112 | lexicon.GetString(10_0101); // "一十万零一百零一" 113 | lexicon.GetString(10_1001); // "一十万一千零一" 114 | lexicon.GetString(10_1010); // "一十万一千零一十" 115 | 116 | lexicon.GetNumber("一十万零一"); // 10_0001 117 | lexicon.GetNumber("一十万零一百零一"); // 10_0101 118 | lexicon.GetNumber("一十万一千零一"); // 10_1001 119 | lexicon.GetNumber("一十万一千零一十"); // 10_1010 120 | ``` 121 | 122 | #### 大数读法 123 | 124 | ##### 流行读法 125 | 126 | 亿级以上使用(万亿、亿亿、万亿亿、亿亿亿、万亿亿亿): 127 | 128 | ```csharp 129 | var lexicon = Lexicon.Number; 130 | 131 | // "一万亿亿亿二千三百四十五亿亿亿六千七百八十九万亿亿零一百二十三亿亿四千五百六十七万亿八千九百零一亿二千三百四十五万六千七百八十九" 132 | lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m); 133 | 134 | // 12345678901234567890123456789 135 | lexicon.GetNumber("一万亿亿亿二千三百四十五亿亿亿六千七百八十九万亿亿零一百二十三亿亿四千五百六十七万亿八千九百零一亿二千三百四十五万六千七百八十九"); 136 | ``` 137 | 138 | ##### 经典读法 139 | 140 | 亿级以上使用(兆、京、垓、秭、穰): 141 | 142 | ```c# 143 | var lexicon = Lexicon.NumberWith(NumberMode.Classical); 144 | 145 | // "一穰二千三百四十五秭六千七百八十九垓零一百二十三京四千五百六十七兆八千九百零一亿二千三百四十五万六千七百八十九" 146 | lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m); 147 | 148 | // 12345678901234567890123456789 149 | lexicon.GetNumber("一穰二千三百四十五秭六千七百八十九垓零一百二十三京四千五百六十七兆八千九百零一亿二千三百四十五万六千七百八十九"); 150 | ``` 151 | 152 |
153 | 154 | ### 编号读法 155 | 156 | ```c# 157 | var lexicon = Lexicon.NumberWith(NumberMode.Code); 158 | lexicon.GetString(10_0001); // "一〇〇〇〇一" 159 | lexicon.GetString(10_0101); // "一〇〇一〇一" 160 | lexicon.GetString(10_1001); // "一〇一〇〇一" 161 | lexicon.GetString(10_1010); // "一〇一〇一〇" 162 | 163 | lexicon.GetNumber("一〇〇〇〇一"); // 10_0001 164 | lexicon.GetNumber("一〇〇一〇一"); // 10_0101 165 | lexicon.GetNumber("一〇一〇〇一"); // 10_1001 166 | lexicon.GetNumber("一〇一〇一〇"); // 10_1010 167 | ``` 168 | 169 |
170 | 171 | ### 货币读法 172 | 173 | ```c# 174 | var lexicon = Lexicon.Currency; 175 | 176 | lexicon.GetString(1); // "一元整" 177 | lexicon.GetString(10_0001); // "一十万零一元整" 178 | lexicon.GetString(10_0101); // "一十万零一百零一元整" 179 | lexicon.GetString(10_1001); // "一十万一千零一元整" 180 | lexicon.GetString(10_1010); // "一十万一千零一十元整" 181 | lexicon.GetString(10_0001.2m); // "一十万零一元二角整" 182 | lexicon.GetString(10_0001.23m); // "一十万零一元二角三分" 183 | lexicon.GetString(10_0001.03m); // "一十万零一元零三分" 184 | 185 | lexicon.GetNumber("一元整"); // 1 186 | lexicon.GetNumber("一十万零一元整"); // 10_0001 187 | lexicon.GetNumber("一十万零一百零一元整"); // 10_0101 188 | lexicon.GetNumber("一十万一千零一元整"); // 10_1001 189 | lexicon.GetNumber("一十万一千零一十元整"); // 10_1010 190 | lexicon.GetNumber("一十万零一元二角整"); // 10_0001.2m 191 | lexicon.GetNumber("一十万零一元二角三分"); // 10_0001.23m 192 | lexicon.GetNumber("一十万零一元零三分"); // 10_0001.03m 193 | ``` 194 | 195 |
-------------------------------------------------------------------------------- /Tests/Chinese.Test/Chinese.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | false 6 | preview 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/ConverterTests.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Test.Util; 2 | using Xunit; 3 | 4 | namespace Chinese.Test; 5 | 6 | public class ConverterTests 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | var lexicon = MySqlLexicon.UseDefault(); 12 | Assert.Equal("免費,跨平臺,開源!", lexicon.ToTraditional("免费,跨平台,开源!")); 13 | Assert.Equal("免费,跨平台,开源!", lexicon.ToSimplified("免費,跨平臺,開源!")); 14 | } 15 | 16 | [Fact] 17 | public void Test2() 18 | { 19 | var lexicon = MySqlLexicon.UseDefault(); 20 | Assert.Equal("皇后在國王後面。", lexicon.ToTraditional("皇后在国王后面。")); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/CurrencyTests.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Lexicons; 2 | using Xunit; 3 | 4 | namespace Chinese.Test; 5 | 6 | public class CurrencyTests 7 | { 8 | [Fact] 9 | public void Test() 10 | { 11 | var lexicon = Lexicon.Currency; 12 | 13 | Assert.Equal("一元整", lexicon.GetString(1)); 14 | Assert.Equal("一十万零一元整", lexicon.GetString(10_0001)); 15 | Assert.Equal("一十万零一百零一元整", lexicon.GetString(10_0101)); 16 | Assert.Equal("一十万一千零一元整", lexicon.GetString(10_1001)); 17 | Assert.Equal("一十万一千零一十元整", lexicon.GetString(10_1010)); 18 | Assert.Equal("一十万零一元二角整", lexicon.GetString(10_0001.2m)); 19 | Assert.Equal("一十万零一元二角三分", lexicon.GetString(10_0001.23m)); 20 | Assert.Equal("一十万零一元零三分", lexicon.GetString(10_0001.03m)); 21 | 22 | Assert.Equal(1, lexicon.GetNumber("一元整")); 23 | Assert.Equal(10_0001, lexicon.GetNumber("一十万零一元整")); 24 | Assert.Equal(10_0101, lexicon.GetNumber("一十万零一百零一元整")); 25 | Assert.Equal(10_1001, lexicon.GetNumber("一十万一千零一元整")); 26 | Assert.Equal(10_1010, lexicon.GetNumber("一十万一千零一十元整")); 27 | Assert.Equal(10_0001.2m, lexicon.GetNumber("一十万零一元二角整")); 28 | Assert.Equal(10_0001.23m, lexicon.GetNumber("一十万零一元二角三分")); 29 | Assert.Equal(10_0001.03m, lexicon.GetNumber("一十万零一元零三分")); 30 | } 31 | 32 | [Fact] 33 | public void UpperTest() 34 | { 35 | var lexicon = Lexicon.CurrencyWith(NumberMode.Upper); 36 | 37 | Assert.Equal("壹圆整", lexicon.GetString(1)); 38 | Assert.Equal("壹拾万零壹圆整", lexicon.GetString(10_0001)); 39 | Assert.Equal("壹拾万零壹佰零壹圆整", lexicon.GetString(10_0101)); 40 | Assert.Equal("壹拾万壹仟零壹圆整", lexicon.GetString(10_1001)); 41 | Assert.Equal("壹拾万壹仟零壹拾圆整", lexicon.GetString(10_1010)); 42 | Assert.Equal("壹拾万零壹圆贰角整", lexicon.GetString(10_0001.2m)); 43 | Assert.Equal("壹拾万零壹圆贰角叁分", lexicon.GetString(10_0001.23m)); 44 | Assert.Equal("壹拾万零壹圆零叁分", lexicon.GetString(10_0001.03m)); 45 | 46 | Assert.Equal(1, lexicon.GetNumber("壹圆整")); 47 | Assert.Equal(10_0001, lexicon.GetNumber("壹拾万零壹圆整")); 48 | Assert.Equal(10_0101, lexicon.GetNumber("壹拾万零壹佰零壹圆整")); 49 | Assert.Equal(10_1001, lexicon.GetNumber("壹拾万壹仟零壹圆整")); 50 | Assert.Equal(10_1010, lexicon.GetNumber("壹拾万壹仟零壹拾圆整")); 51 | Assert.Equal(10_0001.2m, lexicon.GetNumber("壹拾万零壹圆贰角整")); 52 | Assert.Equal(10_0001.23m, lexicon.GetNumber("壹拾万零壹圆贰角叁分")); 53 | Assert.Equal(10_0001.03m, lexicon.GetNumber("壹拾万零壹圆零叁分")); 54 | } 55 | 56 | [Fact] 57 | public void LastZeroTest() 58 | { 59 | var lexicon = Lexicon.Currency; 60 | 61 | Assert.Equal("一十万元整", lexicon.GetString(10_0000m)); 62 | Assert.Equal("一十亿元整", lexicon.GetString(10_0000_0000m)); 63 | Assert.Equal("一十亿零一元整", lexicon.GetString(10_0000_0001m)); 64 | Assert.Equal("一十亿零一千零一元整", lexicon.GetString(10_0000_1001m)); 65 | Assert.Equal("一十亿零一百万一千零一元整", lexicon.GetString(10_0100_1001m)); 66 | Assert.Equal("一千零二十万三千零四十元整", lexicon.GetString(1020_3040m)); 67 | 68 | Assert.Equal(10_0000m, lexicon.GetNumber("一十万元整")); 69 | Assert.Equal(10_0000_0000m, lexicon.GetNumber("一十亿元整")); 70 | Assert.Equal(10_0000_0001m, lexicon.GetNumber("一十亿零一元整")); 71 | Assert.Equal(10_0000_1001m, lexicon.GetNumber("一十亿零一千零一元整")); 72 | Assert.Equal(10_0100_1001m, lexicon.GetNumber("一十亿零一百万一千零一元整")); 73 | Assert.Equal(1020_3040m, lexicon.GetNumber("一千零二十万三千零四十元整")); 74 | } 75 | 76 | [Fact] 77 | public void FirstZeroTest() 78 | { 79 | var lexicon = Lexicon.Currency; 80 | 81 | Assert.Equal("零元一角整", lexicon.GetString(0.1m)); 82 | Assert.Equal("零元零一分", lexicon.GetString(0.01m)); 83 | 84 | Assert.Equal(0.1m, lexicon.GetNumber("零元一角整")); 85 | Assert.Equal(0.01m, lexicon.GetNumber("零元零一分")); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/NumberTests.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Lexicons; 2 | using System; 3 | using Xunit; 4 | 5 | namespace Chinese.Test; 6 | 7 | public class NumberTests 8 | { 9 | [Fact] 10 | public void Test() 11 | { 12 | var lexicon = Lexicon.Number; 13 | 14 | Assert.Equal("一", lexicon.GetString(1)); 15 | Assert.Equal("一十万零一", lexicon.GetString(10_0001)); 16 | Assert.Equal("一十万零一百零一", lexicon.GetString(10_0101)); 17 | Assert.Equal("一十万一千零一", lexicon.GetString(10_1001)); 18 | Assert.Equal("一十万一千零一十", lexicon.GetString(10_1010)); 19 | 20 | Assert.Equal(1, lexicon.GetNumber("一")); 21 | Assert.Equal(10_0001, lexicon.GetNumber("一十万零一")); 22 | Assert.Equal(10_0101, lexicon.GetNumber("一十万零一百零一")); 23 | Assert.Equal(10_1001, lexicon.GetNumber("一十万一千零一")); 24 | Assert.Equal(10_1010, lexicon.GetNumber("一十万一千零一十")); 25 | } 26 | 27 | [Fact] 28 | public void UpperTest() 29 | { 30 | var lexicon = Lexicon.NumberWith(NumberMode.Upper); 31 | 32 | Assert.Equal("壹", lexicon.GetString(1)); 33 | Assert.Equal("壹拾万零壹", lexicon.GetString(10_0001)); 34 | Assert.Equal("壹拾万零壹佰零壹", lexicon.GetString(10_0101)); 35 | Assert.Equal("壹拾万壹仟零壹", lexicon.GetString(10_1001)); 36 | Assert.Equal("壹拾万壹仟零壹拾", lexicon.GetString(10_1010)); 37 | 38 | Assert.Equal(1, lexicon.GetNumber("壹")); 39 | Assert.Equal(10_0001, lexicon.GetNumber("壹拾万零壹")); 40 | Assert.Equal(10_0101, lexicon.GetNumber("壹拾万零壹佰零壹")); 41 | Assert.Equal(10_1001, lexicon.GetNumber("壹拾万壹仟零壹")); 42 | Assert.Equal(10_1010, lexicon.GetNumber("壹拾万壹仟零壹拾")); 43 | } 44 | 45 | [Fact] 46 | public void ConciseTest() 47 | { 48 | var lexicon = Lexicon.NumberWith(NumberMode.Concise); 49 | 50 | Assert.Equal("一", lexicon.GetString(1)); 51 | Assert.Equal("十万零一", lexicon.GetString(10_0001)); 52 | Assert.Equal("十万零一百零一", lexicon.GetString(10_0101)); 53 | Assert.Equal("十万一千零一", lexicon.GetString(10_1001)); 54 | Assert.Equal("十万一千零一十", lexicon.GetString(10_1010)); 55 | 56 | Assert.Equal(1, lexicon.GetNumber("一")); 57 | Assert.Equal(10_0001, lexicon.GetNumber("十万零一")); 58 | Assert.Equal(10_0101, lexicon.GetNumber("十万零一百零一")); 59 | Assert.Equal(10_1001, lexicon.GetNumber("十万一千零一")); 60 | Assert.Equal(10_1010, lexicon.GetNumber("十万一千零一十")); 61 | } 62 | 63 | [Fact] 64 | public void ConciseUpperTest() 65 | { 66 | var lexicon = Lexicon.NumberWith(NumberMode.Concise | NumberMode.Upper); 67 | 68 | Assert.Equal("壹", lexicon.GetString(1)); 69 | Assert.Equal("拾万零壹", lexicon.GetString(10_0001)); 70 | Assert.Equal("拾万零壹佰零壹", lexicon.GetString(10_0101)); 71 | Assert.Equal("拾万壹仟零壹", lexicon.GetString(10_1001)); 72 | Assert.Equal("拾万壹仟零壹拾", lexicon.GetString(10_1010)); 73 | 74 | Assert.Equal(1, lexicon.GetNumber("壹")); 75 | Assert.Equal(10_0001, lexicon.GetNumber("拾万零壹")); 76 | Assert.Equal(10_0101, lexicon.GetNumber("拾万零壹佰零壹")); 77 | Assert.Equal(10_1001, lexicon.GetNumber("拾万壹仟零壹")); 78 | Assert.Equal(10_1010, lexicon.GetNumber("拾万壹仟零壹拾")); 79 | } 80 | 81 | [Fact] 82 | public void CodeTest() 83 | { 84 | var lexicon = Lexicon.NumberWith(NumberMode.Code); 85 | 86 | Assert.Equal("一〇〇〇〇一", lexicon.GetString(10_0001)); 87 | Assert.Equal("一〇〇一〇一", lexicon.GetString(10_0101)); 88 | Assert.Equal("一〇一〇〇一", lexicon.GetString(10_1001)); 89 | Assert.Equal("一〇一〇一〇", lexicon.GetString(10_1010)); 90 | 91 | Assert.Equal(10_0001, lexicon.GetNumber("一〇〇〇〇一")); 92 | Assert.Equal(10_0101, lexicon.GetNumber("一〇〇一〇一")); 93 | Assert.Equal(10_1001, lexicon.GetNumber("一〇一〇〇一")); 94 | Assert.Equal(10_1010, lexicon.GetNumber("一〇一〇一〇")); 95 | } 96 | 97 | [Fact] 98 | public void CodeUpperTest() 99 | { 100 | var lexicon = Lexicon.NumberWith(NumberMode.Code | NumberMode.Upper); 101 | 102 | Assert.Equal("壹零零零零壹", lexicon.GetString(10_0001)); 103 | Assert.Equal("壹零零壹零壹", lexicon.GetString(10_0101)); 104 | Assert.Equal("壹零壹零零壹", lexicon.GetString(10_1001)); 105 | Assert.Equal("壹零壹零壹零", lexicon.GetString(10_1010)); 106 | 107 | Assert.Equal(10_0001, lexicon.GetNumber("壹零零零零壹")); 108 | Assert.Equal(10_0101, lexicon.GetNumber("壹零零壹零壹")); 109 | Assert.Equal(10_1001, lexicon.GetNumber("壹零壹零零壹")); 110 | Assert.Equal(10_1010, lexicon.GetNumber("壹零壹零壹零")); 111 | } 112 | 113 | [Fact] 114 | public void BigIntegerTest() 115 | { 116 | var lexicon = Lexicon.Number; 117 | var expected = "一万亿亿亿二千三百四十五亿亿亿六千七百八十九万亿亿零一百二十三亿亿四千五百六十七万亿八千九百零一亿二千三百四十五万六千七百八十九"; 118 | 119 | Assert.Equal(expected, lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m)); 120 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, lexicon.GetNumber(expected)); 121 | } 122 | 123 | [Fact] 124 | public void BigIntegerUpperTest() 125 | { 126 | var lexicon = Lexicon.NumberWith(NumberMode.Upper); 127 | var expected = "壹万亿亿亿贰仟叁佰肆拾伍亿亿亿陆仟柒佰捌拾玖万亿亿零壹佰贰拾叁亿亿肆仟伍佰陆拾柒万亿捌仟玖佰零壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖"; 128 | 129 | Assert.Equal(expected, lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m)); 130 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, lexicon.GetNumber(expected)); 131 | } 132 | 133 | [Fact] 134 | public void BigIntegerTraditionalTest() 135 | { 136 | var lexicon = Lexicon.NumberWith(NumberMode.Classical); 137 | var expected = "一穰二千三百四十五秭六千七百八十九垓零一百二十三京四千五百六十七兆八千九百零一亿二千三百四十五万六千七百八十九"; 138 | 139 | Assert.Equal(expected, lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m)); 140 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, lexicon.GetNumber(expected)); 141 | } 142 | 143 | [Fact] 144 | public void BigIntegerTraditionalUpperTest() 145 | { 146 | var lexicon = Lexicon.NumberWith(NumberMode.Classical | NumberMode.Upper); 147 | var expected = "壹穰贰仟叁佰肆拾伍秭陆仟柒佰捌拾玖垓零壹佰贰拾叁京肆仟伍佰陆拾柒兆捌仟玖佰零壹亿贰仟叁佰肆拾伍万陆仟柒佰捌拾玖"; 148 | 149 | Assert.Equal(expected, lexicon.GetString(1_2345_6789_0123_4567_8901_2345_6789m)); 150 | Assert.Equal(1_2345_6789_0123_4567_8901_2345_6789m, lexicon.GetNumber(expected)); 151 | } 152 | 153 | [Fact] 154 | public void MutilZeroTest() 155 | { 156 | var lexicon = Lexicon.Number; 157 | Assert.Equal("二十亿零一", lexicon.GetString(20_0000_0001)); 158 | Assert.Equal("二十万亿零一", lexicon.GetString(20_0000_0000_0001)); 159 | Assert.Equal(20_0000_0001, lexicon.GetNumber("二十亿零一")); 160 | Assert.Equal(20_0000_0000_0001, lexicon.GetNumber("二十万亿零一")); 161 | } 162 | 163 | [Fact] 164 | public void MutilZeroTraditionalTest() 165 | { 166 | var lexicon = Lexicon.NumberWith(NumberMode.Classical); 167 | Assert.Equal("二十亿零一", lexicon.GetString(20_0000_0001)); 168 | Assert.Equal("二十兆零一", lexicon.GetString(20_0000_0000_0001)); 169 | Assert.Equal(20_0000_0001, lexicon.GetNumber("二十亿零一")); 170 | Assert.Equal(20_0000_0000_0001, lexicon.GetNumber("二十兆零一")); 171 | } 172 | 173 | [Fact] 174 | public void AliasTest() 175 | { 176 | var lexicon = Lexicon.Number; 177 | Assert.Equal(22222, lexicon.GetNumber("两万二千两百二十二")); 178 | Assert.Throws(() => lexicon.GetNumber("两")); 179 | Assert.Throws(() => lexicon.GetNumber("两万二千两百二十两")); 180 | } 181 | 182 | } 183 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/PinyinTest.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Test.Util; 2 | using Xunit; 3 | 4 | namespace Chinese.Test; 5 | 6 | public class PinyinTest 7 | { 8 | [Fact] 9 | public void SimpleTest1() 10 | { 11 | var lexicon = MySqlLexicon.UseDefault(); 12 | var str = "免费,跨平台,开源!"; 13 | Assert.Equal("mian3 fei4,kua4 ping2 tai2,kai1 yuan2!", lexicon.GetPinyin(str)); 14 | Assert.Equal("mian fei,kua ping tai,kai yuan!", lexicon.GetPinyin(str, PinyinFormat.WithoutTone)); 15 | Assert.Equal("miǎn fèi,kuà píng tái,kāi yuán!", lexicon.GetPinyin(str, PinyinFormat.Phonetic)); 16 | Assert.Equal("mf,kpt,ky!", lexicon.GetPinyin(str, PinyinFormat.InitialConsonant)); 17 | } 18 | 19 | [Fact] 20 | public void SimpleTest2() 21 | { 22 | var lexicon = MySqlLexicon.UseDefault(); 23 | var str = "Chinese是基于.NET平台的Chinese库。"; 24 | Assert.Equal("Chinese shi4 ji1 yu2 .NET ping2 tai2 de5 Chinese ku4。", lexicon.GetPinyin(str)); 25 | Assert.Equal("Chinese shi ji yu .NET ping tai de Chinese ku。", lexicon.GetPinyin(str, PinyinFormat.WithoutTone)); 26 | Assert.Equal("Chinese shì jī yú .NET píng tái de Chinese kù。", lexicon.GetPinyin(str, PinyinFormat.Phonetic)); 27 | Assert.Equal("Chinese sjy .NET ptd Chinese k。", lexicon.GetPinyin(str, PinyinFormat.InitialConsonant)); 28 | } 29 | 30 | [Fact] 31 | public void NormalTest() 32 | { 33 | var lexicon = MySqlLexicon.UseDefault(); 34 | var str = "温度设定为1度。"; 35 | 36 | // 错误, 需要词性分析 37 | //TODO: 为 = wéi 38 | Assert.Equal("wen1 du4 she4 ding4 wei4 1 du4。", lexicon.GetPinyin(str)); 39 | } 40 | 41 | [Fact] 42 | public void ChineseLexiconTest1() 43 | { 44 | var lexicon = MySqlLexicon.UseDefault(); 45 | var str = "他是来自重庆的重量级选手。"; 46 | Assert.Equal("ta1 shi4 lai2 zi4 chong2 qing4 de5 zhong4 liang4 ji2 xuan3 shou3。", lexicon.GetPinyin(str)); 47 | } 48 | 49 | [Fact] 50 | public void NotSameWordTest() 51 | { 52 | var lexicon = MySqlLexicon.UseDefault(); 53 | Assert.Equal("伺服器中止了服務。", lexicon.ToTraditional("服务器中止了服务。")); 54 | Assert.Equal("fu2 wu4 qi4 zhong1 zhi3 le5 fu2 wu4。", lexicon.GetPinyin("服务器中止了服务。", ChineseType.Simplified)); 55 | Assert.Equal("si4 fu2 qi4 zhong1 zhi3 le5 fu2 wu4。", lexicon.GetPinyin("伺服器中止了服務。", ChineseType.Traditional)); 56 | } 57 | 58 | [Fact] 59 | public void ParagraghTest() 60 | { 61 | var lexicon = MySqlLexicon.UseDefault(); 62 | var text = @"这地方的火烧云变化极多,一会儿红彤彤的,一会儿金灿灿的,一会儿半紫半黄,一会儿半灰半百合色。葡萄灰、梨黄、茄子紫,这些颜色天空都有。还有些说也说不出来、见也没见过的颜色。 63 | 64 | 一会儿,天空出现一匹马,马头向南,马尾向西。马是跪着的,像等人骑上它的背,它才站起来似的。过了两三秒钟,那匹马大起来了,腿伸开了,脖子也长了,尾巴却不见了。看的人正在寻找马尾巴,那匹马变模糊了。 65 | 66 | 忽然又来了一条大狗。那条狗十分凶猛,在向前跑,后边似乎还跟着好几条小狗。跑着跑着,小狗不知哪里去了,大狗也不见了。 67 | 68 | 接着又来了一头大狮子,跟庙门前的石头狮子一模一样,也那么大,也那样蹲着,很威武很镇静地蹲着。可是一转眼就变了,再也找不着了。"; 69 | 70 | var pinyin = lexicon.GetPinyin(text, ChineseType.Simplified, PinyinFormat.Phonetic); 71 | 72 | // 错误, 需要词性分析 73 | //TODO: 的背 = de / bēi 74 | //TODO: 还跟着 = huán / gēn zhe 75 | Assert.Equal( 76 | """ 77 | zhè dì fāng de huǒ shāo yún biàn huà jí duō,yī huì er hóng tóng tóng de,yī huì er jīn càn càn de,yī huì er bàn zǐ bàn huáng,yī huì er bàn huī bàn bǎi hé sè。pú táo huī、lí huáng、qié zi zǐ,zhè xiē yán sè tiān kōng dōu yǒu。huán yǒu xiē shuō yě shuō bù chū lái、jiàn yě méi jiàn guò de yán sè。 78 | 79 | yī huì er,tiān kōng chū xiàn yī pǐ mǎ,mǎ tóu xiàng nán,mǎ wěi xiàng xī。mǎ shì guì zhe de,xiàng děng rén qí shàng tā de bēi,tā cái zhàn qǐ lái shì de。guò le liǎng sān miǎo zhōng,nà pǐ mǎ dà qǐ lái le,tuǐ shēn kāi le,bó zi yě zhǎng le,wěi bā què bù jiàn le。kàn de rén zhèng zài xún zhǎo mǎ wěi bā,nà pǐ mǎ biàn mó hú le。 80 | 81 | hū rán yòu lái le yī tiáo dà gǒu。nà tiáo gǒu shí fēn xiōng měng,zài xiàng qián pǎo,hòu biān sì hū huán gēn zhe hǎo jǐ tiáo xiǎo gǒu。pǎo zhe pǎo zhe,xiǎo gǒu bù zhī nǎ lǐ qù le,dà gǒu yě bù jiàn le。 82 | 83 | jiē zhe yòu lái le yī tóu dà shī zi,gēn miào mén qián de shí tou shī zi yī mú yī yàng,yě nà me dà,yě nà yàng dūn zhe,hěn wēi wǔ hěn zhèn jìng dì dūn zhe。kě shì yī zhuǎn yǎn jiù biàn le,zài yě zhǎo bù zháo le。 84 | """ 85 | , pinyin); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/RegionTests.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Mainland; 2 | using NStandard; 3 | using System.Linq; 4 | using Xunit; 5 | 6 | namespace Chinese.Test; 7 | 8 | public class RegionTests 9 | { 10 | [Fact] 11 | public void Test1() 12 | { 13 | var result = Generator.Build(); 14 | var country = result.Cities.First(x => x.Name == "北京市"); 15 | Assert.Equal("东城区,西城区", country.Countries.Select(x => x.Name).Take(2).Join(",")); 16 | } 17 | 18 | [Fact] 19 | public void Test2() 20 | { 21 | var result = Generator.Build(); 22 | var country = result.Countries.First(x => x.Name == "长安区"); 23 | Assert.Equal("石家庄市", country.City.Name); 24 | Assert.Equal("河北省", country.Province.Name); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/TokenizerTests.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Test.Util; 2 | using System.Linq; 3 | using Xunit; 4 | 5 | namespace Chinese.Test; 6 | 7 | public class TokenizerTests 8 | { 9 | [Fact] 10 | public void Test1() 11 | { 12 | var lexicon = MySqlLexicon.UseDefault(); 13 | var sentence = "中国北京是直辖市,重庆也是直辖市。"; 14 | 15 | var words = lexicon.SplitWords(sentence, ChineseType.Simplified); 16 | var exceptedWords = new[] { "中国", "北京", "是", "直辖市", ",", "重庆", "也是", "直辖市", "。" }; 17 | Assert.Equal(exceptedWords, [.. words.Select(x => x.Simplified)]); 18 | 19 | var pinyin = lexicon.GetPinyin(sentence, PinyinFormat.Phonetic); 20 | Assert.Equal("zhōng guó běi jīng shì zhí xiá shì,chóng qìng yě shì zhí xiá shì。", pinyin); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /Tests/Chinese.Test/Util/MySqlLexicon.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Data; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace Chinese.Test.Util; 5 | 6 | public class MySqlLexicon : Lexicon 7 | { 8 | public static MySqlLexicon UseDefault() 9 | { 10 | var mysqlConnectionString = "server=127.0.0.1;port=33306;user=root;password=root;database=chinese"; 11 | var mysqlOptions = new DbContextOptionsBuilder().UseMySql(mysqlConnectionString, ServerVersion.AutoDetect(mysqlConnectionString), null).Options; 12 | 13 | var context = new ChineseDbContext(mysqlOptions); 14 | return new MySqlLexicon(context); 15 | } 16 | 17 | public MySqlLexicon(ChineseDbContext context) 18 | { 19 | Add(context.Words); 20 | Add(context.Chars); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "dotnet-ef": { 6 | "version": "6.0.11", 7 | "commands": [ 8 | "dotnet-ef" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/ApplicationDbContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Data; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Design; 4 | 5 | namespace DbCreator.MySql; 6 | 7 | public class ApplicationDbContextFactory : IDesignTimeDbContextFactory 8 | { 9 | public ChineseDbContext CreateDbContext(string[] args) 10 | { 11 | var mysqlConnectionString = "server=127.0.0.1;port=33306;user=root;password=root;database=chinese"; 12 | var mysqlOptions = new DbContextOptionsBuilder().UseMySql( 13 | mysqlConnectionString, 14 | ServerVersion.AutoDetect(mysqlConnectionString), 15 | b => b.MigrationsAssembly("DbCreator.MySql") 16 | ).Options; 17 | 18 | return new ChineseDbContext(mysqlOptions); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/DbCreator.MySql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20221112224627_202211130646.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20221112224627_202211130646")] 15 | partial class _202211130646 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("IsPolyphone") 35 | .HasColumnType("tinyint(1)"); 36 | 37 | b.Property("Pinyins") 38 | .IsRequired() 39 | .HasColumnType("longtext"); 40 | 41 | b.Property("Simplified") 42 | .IsRequired() 43 | .HasColumnType("longtext"); 44 | 45 | b.Property("SimplifiedPinyin") 46 | .IsRequired() 47 | .HasColumnType("longtext"); 48 | 49 | b.Property("Traditional") 50 | .IsRequired() 51 | .HasColumnType("longtext"); 52 | 53 | b.Property("TraditionalPinyin") 54 | .IsRequired() 55 | .HasColumnType("longtext"); 56 | 57 | b.Property("Types") 58 | .HasColumnType("int"); 59 | 60 | b.HasKey("Unicode"); 61 | 62 | b.ToTable("Chars"); 63 | }); 64 | 65 | modelBuilder.Entity("Chinese.Data.Data.NumericWord", b => 66 | { 67 | b.Property("Id") 68 | .ValueGeneratedOnAdd() 69 | .HasColumnType("char(36)"); 70 | 71 | b.Property("Simplified") 72 | .IsRequired() 73 | .HasColumnType("longtext"); 74 | 75 | b.Property("SimplifiedPinyin") 76 | .IsRequired() 77 | .HasColumnType("longtext"); 78 | 79 | b.Property("Traditional") 80 | .IsRequired() 81 | .HasColumnType("longtext"); 82 | 83 | b.Property("TraditionalPinyin") 84 | .IsRequired() 85 | .HasColumnType("longtext"); 86 | 87 | b.Property("Type") 88 | .HasColumnType("int"); 89 | 90 | b.Property("Value") 91 | .HasColumnType("int"); 92 | 93 | b.HasKey("Id"); 94 | 95 | b.ToTable("NumericWords"); 96 | }); 97 | 98 | modelBuilder.Entity("Chinese.Word", b => 99 | { 100 | b.Property("Id") 101 | .ValueGeneratedOnAdd() 102 | .HasColumnType("char(36)"); 103 | 104 | b.Property("Simplified") 105 | .IsRequired() 106 | .HasColumnType("longtext"); 107 | 108 | b.Property("SimplifiedPinyin") 109 | .IsRequired() 110 | .HasColumnType("longtext"); 111 | 112 | b.Property("Traditional") 113 | .IsRequired() 114 | .HasColumnType("longtext"); 115 | 116 | b.Property("TraditionalPinyin") 117 | .IsRequired() 118 | .HasColumnType("longtext"); 119 | 120 | b.Property("Type") 121 | .HasColumnType("int"); 122 | 123 | b.HasKey("Id"); 124 | 125 | b.ToTable("Words"); 126 | }); 127 | #pragma warning restore 612, 618 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20221112224627_202211130646.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Metadata; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | #nullable disable 5 | 6 | namespace DbCreator.MySql.Migrations; 7 | 8 | public partial class _202211130646 : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.AlterDatabase() 13 | .Annotation("MySql:CharSet", "utf8mb4"); 14 | 15 | migrationBuilder.CreateTable( 16 | name: "Chars", 17 | columns: table => new 18 | { 19 | Unicode = table.Column(type: "int", nullable: false) 20 | .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), 21 | Character = table.Column(type: "varchar(1)", nullable: false) 22 | .Annotation("MySql:CharSet", "utf8mb4"), 23 | Pinyins = table.Column(type: "longtext", nullable: false) 24 | .Annotation("MySql:CharSet", "utf8mb4"), 25 | IsPolyphone = table.Column(type: "tinyint(1)", nullable: false), 26 | Types = table.Column(type: "int", nullable: false), 27 | Simplified = table.Column(type: "longtext", nullable: false) 28 | .Annotation("MySql:CharSet", "utf8mb4"), 29 | Traditional = table.Column(type: "longtext", nullable: false) 30 | .Annotation("MySql:CharSet", "utf8mb4"), 31 | SimplifiedPinyin = table.Column(type: "longtext", nullable: false) 32 | .Annotation("MySql:CharSet", "utf8mb4"), 33 | TraditionalPinyin = table.Column(type: "longtext", nullable: false) 34 | .Annotation("MySql:CharSet", "utf8mb4") 35 | }, 36 | constraints: table => 37 | { 38 | table.PrimaryKey("PK_Chars", x => x.Unicode); 39 | }) 40 | .Annotation("MySql:CharSet", "utf8mb4"); 41 | 42 | migrationBuilder.CreateTable( 43 | name: "NumericWords", 44 | columns: table => new 45 | { 46 | Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), 47 | Type = table.Column(type: "int", nullable: false), 48 | Simplified = table.Column(type: "longtext", nullable: false) 49 | .Annotation("MySql:CharSet", "utf8mb4"), 50 | Traditional = table.Column(type: "longtext", nullable: false) 51 | .Annotation("MySql:CharSet", "utf8mb4"), 52 | SimplifiedPinyin = table.Column(type: "longtext", nullable: false) 53 | .Annotation("MySql:CharSet", "utf8mb4"), 54 | TraditionalPinyin = table.Column(type: "longtext", nullable: false) 55 | .Annotation("MySql:CharSet", "utf8mb4"), 56 | Value = table.Column(type: "int", nullable: false) 57 | }, 58 | constraints: table => 59 | { 60 | table.PrimaryKey("PK_NumericWords", x => x.Id); 61 | }) 62 | .Annotation("MySql:CharSet", "utf8mb4"); 63 | 64 | migrationBuilder.CreateTable( 65 | name: "Words", 66 | columns: table => new 67 | { 68 | Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), 69 | Type = table.Column(type: "int", nullable: false), 70 | Simplified = table.Column(type: "longtext", nullable: false) 71 | .Annotation("MySql:CharSet", "utf8mb4"), 72 | Traditional = table.Column(type: "longtext", nullable: false) 73 | .Annotation("MySql:CharSet", "utf8mb4"), 74 | SimplifiedPinyin = table.Column(type: "longtext", nullable: false) 75 | .Annotation("MySql:CharSet", "utf8mb4"), 76 | TraditionalPinyin = table.Column(type: "longtext", nullable: false) 77 | .Annotation("MySql:CharSet", "utf8mb4") 78 | }, 79 | constraints: table => 80 | { 81 | table.PrimaryKey("PK_Words", x => x.Id); 82 | }) 83 | .Annotation("MySql:CharSet", "utf8mb4"); 84 | } 85 | 86 | protected override void Down(MigrationBuilder migrationBuilder) 87 | { 88 | migrationBuilder.DropTable( 89 | name: "Chars"); 90 | 91 | migrationBuilder.DropTable( 92 | name: "NumericWords"); 93 | 94 | migrationBuilder.DropTable( 95 | name: "Words"); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20221113154648_202211132346.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20221113154648_202211132346")] 15 | partial class _202211132346 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("IsPolyphone") 35 | .HasColumnType("tinyint(1)"); 36 | 37 | b.Property("Pinyins") 38 | .IsRequired() 39 | .HasMaxLength(64) 40 | .HasColumnType("varchar(64)"); 41 | 42 | b.Property("Simplified") 43 | .IsRequired() 44 | .HasMaxLength(64) 45 | .HasColumnType("varchar(64)"); 46 | 47 | b.Property("SimplifiedPinyin") 48 | .IsRequired() 49 | .HasMaxLength(64) 50 | .HasColumnType("varchar(64)"); 51 | 52 | b.Property("Traditional") 53 | .IsRequired() 54 | .HasMaxLength(64) 55 | .HasColumnType("varchar(64)"); 56 | 57 | b.Property("TraditionalPinyin") 58 | .IsRequired() 59 | .HasMaxLength(64) 60 | .HasColumnType("varchar(64)"); 61 | 62 | b.Property("Types") 63 | .HasColumnType("int"); 64 | 65 | b.HasKey("Unicode"); 66 | 67 | b.ToTable("Chars"); 68 | }); 69 | 70 | modelBuilder.Entity("Chinese.Data.Data.NumericWord", b => 71 | { 72 | b.Property("Id") 73 | .ValueGeneratedOnAdd() 74 | .HasColumnType("char(36)"); 75 | 76 | b.Property("Simplified") 77 | .IsRequired() 78 | .HasMaxLength(64) 79 | .HasColumnType("varchar(64)"); 80 | 81 | b.Property("SimplifiedPinyin") 82 | .IsRequired() 83 | .HasMaxLength(64) 84 | .HasColumnType("varchar(64)"); 85 | 86 | b.Property("Traditional") 87 | .IsRequired() 88 | .HasMaxLength(64) 89 | .HasColumnType("varchar(64)"); 90 | 91 | b.Property("TraditionalPinyin") 92 | .IsRequired() 93 | .HasMaxLength(64) 94 | .HasColumnType("varchar(64)"); 95 | 96 | b.Property("Type") 97 | .HasColumnType("int"); 98 | 99 | b.Property("Value") 100 | .HasColumnType("int"); 101 | 102 | b.HasKey("Id"); 103 | 104 | b.ToTable("Numerics"); 105 | }); 106 | 107 | modelBuilder.Entity("Chinese.Word", b => 108 | { 109 | b.Property("Id") 110 | .ValueGeneratedOnAdd() 111 | .HasColumnType("char(36)"); 112 | 113 | b.Property("Simplified") 114 | .IsRequired() 115 | .HasMaxLength(64) 116 | .HasColumnType("varchar(64)"); 117 | 118 | b.Property("SimplifiedPinyin") 119 | .IsRequired() 120 | .HasMaxLength(64) 121 | .HasColumnType("varchar(64)"); 122 | 123 | b.Property("Traditional") 124 | .IsRequired() 125 | .HasMaxLength(64) 126 | .HasColumnType("varchar(64)"); 127 | 128 | b.Property("TraditionalPinyin") 129 | .IsRequired() 130 | .HasMaxLength(64) 131 | .HasColumnType("varchar(64)"); 132 | 133 | b.Property("Type") 134 | .HasColumnType("int"); 135 | 136 | b.HasKey("Id"); 137 | 138 | b.ToTable("Words"); 139 | }); 140 | #pragma warning restore 612, 618 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20221113154648_202211132346.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.MySql.Migrations; 6 | 7 | public partial class _202211132346 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.DropPrimaryKey( 12 | name: "PK_NumericWords", 13 | table: "NumericWords"); 14 | 15 | migrationBuilder.RenameTable( 16 | name: "NumericWords", 17 | newName: "Numerics"); 18 | 19 | migrationBuilder.AlterColumn( 20 | name: "TraditionalPinyin", 21 | table: "Words", 22 | type: "varchar(64)", 23 | maxLength: 64, 24 | nullable: false, 25 | oldClrType: typeof(string), 26 | oldType: "longtext") 27 | .Annotation("MySql:CharSet", "utf8mb4") 28 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 29 | 30 | migrationBuilder.AlterColumn( 31 | name: "Traditional", 32 | table: "Words", 33 | type: "varchar(64)", 34 | maxLength: 64, 35 | nullable: false, 36 | oldClrType: typeof(string), 37 | oldType: "longtext") 38 | .Annotation("MySql:CharSet", "utf8mb4") 39 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 40 | 41 | migrationBuilder.AlterColumn( 42 | name: "SimplifiedPinyin", 43 | table: "Words", 44 | type: "varchar(64)", 45 | maxLength: 64, 46 | nullable: false, 47 | oldClrType: typeof(string), 48 | oldType: "longtext") 49 | .Annotation("MySql:CharSet", "utf8mb4") 50 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 51 | 52 | migrationBuilder.AlterColumn( 53 | name: "Simplified", 54 | table: "Words", 55 | type: "varchar(64)", 56 | maxLength: 64, 57 | nullable: false, 58 | oldClrType: typeof(string), 59 | oldType: "longtext") 60 | .Annotation("MySql:CharSet", "utf8mb4") 61 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 62 | 63 | migrationBuilder.AlterColumn( 64 | name: "TraditionalPinyin", 65 | table: "Chars", 66 | type: "varchar(64)", 67 | maxLength: 64, 68 | nullable: false, 69 | oldClrType: typeof(string), 70 | oldType: "longtext") 71 | .Annotation("MySql:CharSet", "utf8mb4") 72 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 73 | 74 | migrationBuilder.AlterColumn( 75 | name: "Traditional", 76 | table: "Chars", 77 | type: "varchar(64)", 78 | maxLength: 64, 79 | nullable: false, 80 | oldClrType: typeof(string), 81 | oldType: "longtext") 82 | .Annotation("MySql:CharSet", "utf8mb4") 83 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 84 | 85 | migrationBuilder.AlterColumn( 86 | name: "SimplifiedPinyin", 87 | table: "Chars", 88 | type: "varchar(64)", 89 | maxLength: 64, 90 | nullable: false, 91 | oldClrType: typeof(string), 92 | oldType: "longtext") 93 | .Annotation("MySql:CharSet", "utf8mb4") 94 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 95 | 96 | migrationBuilder.AlterColumn( 97 | name: "Simplified", 98 | table: "Chars", 99 | type: "varchar(64)", 100 | maxLength: 64, 101 | nullable: false, 102 | oldClrType: typeof(string), 103 | oldType: "longtext") 104 | .Annotation("MySql:CharSet", "utf8mb4") 105 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 106 | 107 | migrationBuilder.AlterColumn( 108 | name: "Pinyins", 109 | table: "Chars", 110 | type: "varchar(64)", 111 | maxLength: 64, 112 | nullable: false, 113 | oldClrType: typeof(string), 114 | oldType: "longtext") 115 | .Annotation("MySql:CharSet", "utf8mb4") 116 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 117 | 118 | migrationBuilder.AlterColumn( 119 | name: "TraditionalPinyin", 120 | table: "Numerics", 121 | type: "varchar(64)", 122 | maxLength: 64, 123 | nullable: false, 124 | oldClrType: typeof(string), 125 | oldType: "longtext") 126 | .Annotation("MySql:CharSet", "utf8mb4") 127 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 128 | 129 | migrationBuilder.AlterColumn( 130 | name: "Traditional", 131 | table: "Numerics", 132 | type: "varchar(64)", 133 | maxLength: 64, 134 | nullable: false, 135 | oldClrType: typeof(string), 136 | oldType: "longtext") 137 | .Annotation("MySql:CharSet", "utf8mb4") 138 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 139 | 140 | migrationBuilder.AlterColumn( 141 | name: "SimplifiedPinyin", 142 | table: "Numerics", 143 | type: "varchar(64)", 144 | maxLength: 64, 145 | nullable: false, 146 | oldClrType: typeof(string), 147 | oldType: "longtext") 148 | .Annotation("MySql:CharSet", "utf8mb4") 149 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 150 | 151 | migrationBuilder.AlterColumn( 152 | name: "Simplified", 153 | table: "Numerics", 154 | type: "varchar(64)", 155 | maxLength: 64, 156 | nullable: false, 157 | oldClrType: typeof(string), 158 | oldType: "longtext") 159 | .Annotation("MySql:CharSet", "utf8mb4") 160 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 161 | 162 | migrationBuilder.AddPrimaryKey( 163 | name: "PK_Numerics", 164 | table: "Numerics", 165 | column: "Id"); 166 | } 167 | 168 | protected override void Down(MigrationBuilder migrationBuilder) 169 | { 170 | migrationBuilder.DropPrimaryKey( 171 | name: "PK_Numerics", 172 | table: "Numerics"); 173 | 174 | migrationBuilder.RenameTable( 175 | name: "Numerics", 176 | newName: "NumericWords"); 177 | 178 | migrationBuilder.AlterColumn( 179 | name: "TraditionalPinyin", 180 | table: "Words", 181 | type: "longtext", 182 | nullable: false, 183 | oldClrType: typeof(string), 184 | oldType: "varchar(64)", 185 | oldMaxLength: 64) 186 | .Annotation("MySql:CharSet", "utf8mb4") 187 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 188 | 189 | migrationBuilder.AlterColumn( 190 | name: "Traditional", 191 | table: "Words", 192 | type: "longtext", 193 | nullable: false, 194 | oldClrType: typeof(string), 195 | oldType: "varchar(64)", 196 | oldMaxLength: 64) 197 | .Annotation("MySql:CharSet", "utf8mb4") 198 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 199 | 200 | migrationBuilder.AlterColumn( 201 | name: "SimplifiedPinyin", 202 | table: "Words", 203 | type: "longtext", 204 | nullable: false, 205 | oldClrType: typeof(string), 206 | oldType: "varchar(64)", 207 | oldMaxLength: 64) 208 | .Annotation("MySql:CharSet", "utf8mb4") 209 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 210 | 211 | migrationBuilder.AlterColumn( 212 | name: "Simplified", 213 | table: "Words", 214 | type: "longtext", 215 | nullable: false, 216 | oldClrType: typeof(string), 217 | oldType: "varchar(64)", 218 | oldMaxLength: 64) 219 | .Annotation("MySql:CharSet", "utf8mb4") 220 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 221 | 222 | migrationBuilder.AlterColumn( 223 | name: "TraditionalPinyin", 224 | table: "Chars", 225 | type: "longtext", 226 | nullable: false, 227 | oldClrType: typeof(string), 228 | oldType: "varchar(64)", 229 | oldMaxLength: 64) 230 | .Annotation("MySql:CharSet", "utf8mb4") 231 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 232 | 233 | migrationBuilder.AlterColumn( 234 | name: "Traditional", 235 | table: "Chars", 236 | type: "longtext", 237 | nullable: false, 238 | oldClrType: typeof(string), 239 | oldType: "varchar(64)", 240 | oldMaxLength: 64) 241 | .Annotation("MySql:CharSet", "utf8mb4") 242 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 243 | 244 | migrationBuilder.AlterColumn( 245 | name: "SimplifiedPinyin", 246 | table: "Chars", 247 | type: "longtext", 248 | nullable: false, 249 | oldClrType: typeof(string), 250 | oldType: "varchar(64)", 251 | oldMaxLength: 64) 252 | .Annotation("MySql:CharSet", "utf8mb4") 253 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 254 | 255 | migrationBuilder.AlterColumn( 256 | name: "Simplified", 257 | table: "Chars", 258 | type: "longtext", 259 | nullable: false, 260 | oldClrType: typeof(string), 261 | oldType: "varchar(64)", 262 | oldMaxLength: 64) 263 | .Annotation("MySql:CharSet", "utf8mb4") 264 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 265 | 266 | migrationBuilder.AlterColumn( 267 | name: "Pinyins", 268 | table: "Chars", 269 | type: "longtext", 270 | nullable: false, 271 | oldClrType: typeof(string), 272 | oldType: "varchar(64)", 273 | oldMaxLength: 64) 274 | .Annotation("MySql:CharSet", "utf8mb4") 275 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 276 | 277 | migrationBuilder.AlterColumn( 278 | name: "TraditionalPinyin", 279 | table: "NumericWords", 280 | type: "longtext", 281 | nullable: false, 282 | oldClrType: typeof(string), 283 | oldType: "varchar(64)", 284 | oldMaxLength: 64) 285 | .Annotation("MySql:CharSet", "utf8mb4") 286 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 287 | 288 | migrationBuilder.AlterColumn( 289 | name: "Traditional", 290 | table: "NumericWords", 291 | type: "longtext", 292 | nullable: false, 293 | oldClrType: typeof(string), 294 | oldType: "varchar(64)", 295 | oldMaxLength: 64) 296 | .Annotation("MySql:CharSet", "utf8mb4") 297 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 298 | 299 | migrationBuilder.AlterColumn( 300 | name: "SimplifiedPinyin", 301 | table: "NumericWords", 302 | type: "longtext", 303 | nullable: false, 304 | oldClrType: typeof(string), 305 | oldType: "varchar(64)", 306 | oldMaxLength: 64) 307 | .Annotation("MySql:CharSet", "utf8mb4") 308 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 309 | 310 | migrationBuilder.AlterColumn( 311 | name: "Simplified", 312 | table: "NumericWords", 313 | type: "longtext", 314 | nullable: false, 315 | oldClrType: typeof(string), 316 | oldType: "varchar(64)", 317 | oldMaxLength: 64) 318 | .Annotation("MySql:CharSet", "utf8mb4") 319 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 320 | 321 | migrationBuilder.AddPrimaryKey( 322 | name: "PK_NumericWords", 323 | table: "NumericWords", 324 | column: "Id"); 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221003235_202302210832.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20230221003235_202302210832")] 15 | partial class _202302210832 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("IsPolyphone") 35 | .HasColumnType("tinyint(1)"); 36 | 37 | b.Property("Pinyins") 38 | .IsRequired() 39 | .HasMaxLength(64) 40 | .HasColumnType("varchar(64)"); 41 | 42 | b.Property("Simplified") 43 | .IsRequired() 44 | .HasMaxLength(64) 45 | .HasColumnType("varchar(64)"); 46 | 47 | b.Property("SimplifiedPinyin") 48 | .IsRequired() 49 | .HasMaxLength(64) 50 | .HasColumnType("varchar(64)"); 51 | 52 | b.Property("Traditional") 53 | .IsRequired() 54 | .HasMaxLength(64) 55 | .HasColumnType("varchar(64)"); 56 | 57 | b.Property("TraditionalPinyin") 58 | .IsRequired() 59 | .HasMaxLength(64) 60 | .HasColumnType("varchar(64)"); 61 | 62 | b.Property("Types") 63 | .HasColumnType("int"); 64 | 65 | b.HasKey("Unicode"); 66 | 67 | b.ToTable("Chars"); 68 | }); 69 | 70 | modelBuilder.Entity("Chinese.Data.Data.NumericWord", b => 71 | { 72 | b.Property("Id") 73 | .ValueGeneratedOnAdd() 74 | .HasColumnType("char(36)"); 75 | 76 | b.Property("Simplified") 77 | .IsRequired() 78 | .HasMaxLength(64) 79 | .HasColumnType("varchar(64)"); 80 | 81 | b.Property("SimplifiedPinyin") 82 | .IsRequired() 83 | .HasMaxLength(64) 84 | .HasColumnType("varchar(64)"); 85 | 86 | b.Property("Traditional") 87 | .IsRequired() 88 | .HasMaxLength(64) 89 | .HasColumnType("varchar(64)"); 90 | 91 | b.Property("TraditionalPinyin") 92 | .IsRequired() 93 | .HasMaxLength(64) 94 | .HasColumnType("varchar(64)"); 95 | 96 | b.Property("Type") 97 | .HasColumnType("int"); 98 | 99 | b.Property("Value") 100 | .HasColumnType("int"); 101 | 102 | b.HasKey("Id"); 103 | 104 | b.ToTable("Numerics"); 105 | }); 106 | 107 | modelBuilder.Entity("Chinese.Word", b => 108 | { 109 | b.Property("Id") 110 | .ValueGeneratedOnAdd() 111 | .HasColumnType("char(36)"); 112 | 113 | b.Property("HashCode") 114 | .HasColumnType("int"); 115 | 116 | b.Property("Simplified") 117 | .IsRequired() 118 | .HasMaxLength(64) 119 | .HasColumnType("varchar(64)"); 120 | 121 | b.Property("SimplifiedPinyin") 122 | .IsRequired() 123 | .HasMaxLength(64) 124 | .HasColumnType("varchar(64)"); 125 | 126 | b.Property("Traditional") 127 | .IsRequired() 128 | .HasMaxLength(64) 129 | .HasColumnType("varchar(64)"); 130 | 131 | b.Property("TraditionalPinyin") 132 | .IsRequired() 133 | .HasMaxLength(64) 134 | .HasColumnType("varchar(64)"); 135 | 136 | b.Property("Type") 137 | .HasColumnType("int"); 138 | 139 | b.HasKey("Id"); 140 | 141 | b.ToTable("Words"); 142 | }); 143 | #pragma warning restore 612, 618 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221003235_202302210832.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.MySql.Migrations; 6 | 7 | public partial class _202302210832 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AddColumn( 12 | name: "HashCode", 13 | table: "Words", 14 | type: "int", 15 | nullable: false, 16 | defaultValue: 0); 17 | } 18 | 19 | protected override void Down(MigrationBuilder migrationBuilder) 20 | { 21 | migrationBuilder.DropColumn( 22 | name: "HashCode", 23 | table: "Words"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221004748_202302210846.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20230221004748_202302210846")] 15 | partial class _202302210846 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("DefaultPinyin") 35 | .IsRequired() 36 | .HasMaxLength(64) 37 | .HasColumnType("varchar(64)"); 38 | 39 | b.Property("IsPolyphone") 40 | .HasColumnType("tinyint(1)"); 41 | 42 | b.Property("Pinyins") 43 | .IsRequired() 44 | .HasMaxLength(64) 45 | .HasColumnType("varchar(64)"); 46 | 47 | b.Property("Simplified") 48 | .IsRequired() 49 | .HasMaxLength(64) 50 | .HasColumnType("varchar(64)"); 51 | 52 | b.Property("SimplifiedPinyin") 53 | .IsRequired() 54 | .HasMaxLength(64) 55 | .HasColumnType("varchar(64)"); 56 | 57 | b.Property("Traditional") 58 | .IsRequired() 59 | .HasMaxLength(64) 60 | .HasColumnType("varchar(64)"); 61 | 62 | b.Property("TraditionalPinyin") 63 | .IsRequired() 64 | .HasMaxLength(64) 65 | .HasColumnType("varchar(64)"); 66 | 67 | b.Property("Types") 68 | .HasColumnType("int"); 69 | 70 | b.HasKey("Unicode"); 71 | 72 | b.ToTable("Chars"); 73 | }); 74 | 75 | modelBuilder.Entity("Chinese.Data.Data.NumericWord", b => 76 | { 77 | b.Property("Id") 78 | .ValueGeneratedOnAdd() 79 | .HasColumnType("char(36)"); 80 | 81 | b.Property("Simplified") 82 | .IsRequired() 83 | .HasMaxLength(64) 84 | .HasColumnType("varchar(64)"); 85 | 86 | b.Property("SimplifiedPinyin") 87 | .IsRequired() 88 | .HasMaxLength(64) 89 | .HasColumnType("varchar(64)"); 90 | 91 | b.Property("Traditional") 92 | .IsRequired() 93 | .HasMaxLength(64) 94 | .HasColumnType("varchar(64)"); 95 | 96 | b.Property("TraditionalPinyin") 97 | .IsRequired() 98 | .HasMaxLength(64) 99 | .HasColumnType("varchar(64)"); 100 | 101 | b.Property("Type") 102 | .HasColumnType("int"); 103 | 104 | b.Property("Value") 105 | .HasColumnType("int"); 106 | 107 | b.HasKey("Id"); 108 | 109 | b.ToTable("Numerics"); 110 | }); 111 | 112 | modelBuilder.Entity("Chinese.Word", b => 113 | { 114 | b.Property("Id") 115 | .ValueGeneratedOnAdd() 116 | .HasColumnType("char(36)"); 117 | 118 | b.Property("HashCode") 119 | .HasColumnType("int"); 120 | 121 | b.Property("Simplified") 122 | .IsRequired() 123 | .HasMaxLength(64) 124 | .HasColumnType("varchar(64)"); 125 | 126 | b.Property("SimplifiedPinyin") 127 | .IsRequired() 128 | .HasMaxLength(64) 129 | .HasColumnType("varchar(64)"); 130 | 131 | b.Property("Traditional") 132 | .IsRequired() 133 | .HasMaxLength(64) 134 | .HasColumnType("varchar(64)"); 135 | 136 | b.Property("TraditionalPinyin") 137 | .IsRequired() 138 | .HasMaxLength(64) 139 | .HasColumnType("varchar(64)"); 140 | 141 | b.Property("Type") 142 | .HasColumnType("int"); 143 | 144 | b.HasKey("Id"); 145 | 146 | b.ToTable("Words"); 147 | }); 148 | #pragma warning restore 612, 618 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221004748_202302210846.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.MySql.Migrations; 6 | 7 | public partial class _202302210846 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AddColumn( 12 | name: "DefaultPinyin", 13 | table: "Chars", 14 | type: "varchar(64)", 15 | maxLength: 64, 16 | nullable: false, 17 | defaultValue: "") 18 | .Annotation("MySql:CharSet", "utf8mb4"); 19 | } 20 | 21 | protected override void Down(MigrationBuilder migrationBuilder) 22 | { 23 | migrationBuilder.DropColumn( 24 | name: "DefaultPinyin", 25 | table: "Chars"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221032034_202302211120.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20230221032034_202302211120")] 15 | partial class _202302211120 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("DefaultPinyin") 35 | .IsRequired() 36 | .HasMaxLength(64) 37 | .HasColumnType("varchar(64)"); 38 | 39 | b.Property("IsPolyphone") 40 | .HasColumnType("tinyint(1)"); 41 | 42 | b.Property("Pinyins") 43 | .IsRequired() 44 | .HasMaxLength(64) 45 | .HasColumnType("varchar(64)"); 46 | 47 | b.Property("Sight") 48 | .HasColumnType("tinyint(1)"); 49 | 50 | b.Property("Simplified") 51 | .IsRequired() 52 | .HasMaxLength(64) 53 | .HasColumnType("varchar(64)"); 54 | 55 | b.Property("Traditional") 56 | .IsRequired() 57 | .HasMaxLength(64) 58 | .HasColumnType("varchar(64)"); 59 | 60 | b.Property("Types") 61 | .HasColumnType("int"); 62 | 63 | b.HasKey("Unicode"); 64 | 65 | b.ToTable("Chars"); 66 | }); 67 | 68 | modelBuilder.Entity("Chinese.Data.Data.NumericWord", b => 69 | { 70 | b.Property("Id") 71 | .ValueGeneratedOnAdd() 72 | .HasColumnType("char(36)"); 73 | 74 | b.Property("Simplified") 75 | .IsRequired() 76 | .HasMaxLength(64) 77 | .HasColumnType("varchar(64)"); 78 | 79 | b.Property("SimplifiedPinyin") 80 | .IsRequired() 81 | .HasMaxLength(64) 82 | .HasColumnType("varchar(64)"); 83 | 84 | b.Property("Traditional") 85 | .IsRequired() 86 | .HasMaxLength(64) 87 | .HasColumnType("varchar(64)"); 88 | 89 | b.Property("TraditionalPinyin") 90 | .IsRequired() 91 | .HasMaxLength(64) 92 | .HasColumnType("varchar(64)"); 93 | 94 | b.Property("Type") 95 | .HasColumnType("int"); 96 | 97 | b.Property("Value") 98 | .HasColumnType("int"); 99 | 100 | b.HasKey("Id"); 101 | 102 | b.ToTable("Numerics"); 103 | }); 104 | 105 | modelBuilder.Entity("Chinese.Word", b => 106 | { 107 | b.Property("Id") 108 | .ValueGeneratedOnAdd() 109 | .HasColumnType("char(36)"); 110 | 111 | b.Property("HashCode") 112 | .HasColumnType("int"); 113 | 114 | b.Property("Simplified") 115 | .IsRequired() 116 | .HasMaxLength(64) 117 | .HasColumnType("varchar(64)"); 118 | 119 | b.Property("SimplifiedPinyin") 120 | .IsRequired() 121 | .HasMaxLength(64) 122 | .HasColumnType("varchar(64)"); 123 | 124 | b.Property("Traditional") 125 | .IsRequired() 126 | .HasMaxLength(64) 127 | .HasColumnType("varchar(64)"); 128 | 129 | b.Property("TraditionalPinyin") 130 | .IsRequired() 131 | .HasMaxLength(64) 132 | .HasColumnType("varchar(64)"); 133 | 134 | b.Property("Type") 135 | .HasColumnType("int"); 136 | 137 | b.HasKey("Id"); 138 | 139 | b.ToTable("Words"); 140 | }); 141 | #pragma warning restore 612, 618 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230221032034_202302211120.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.MySql.Migrations; 6 | 7 | public partial class _202302211120 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AddColumn( 12 | name: "Simplified", 13 | table: "Chars", 14 | type: "varchar(64)", 15 | maxLength: 64, 16 | nullable: false, 17 | defaultValue: "") 18 | .Annotation("MySql:CharSet", "utf8mb4"); 19 | 20 | migrationBuilder.AddColumn( 21 | name: "Traditional", 22 | table: "Chars", 23 | type: "varchar(64)", 24 | maxLength: 64, 25 | nullable: false, 26 | defaultValue: "") 27 | .Annotation("MySql:CharSet", "utf8mb4"); 28 | } 29 | 30 | protected override void Down(MigrationBuilder migrationBuilder) 31 | { 32 | migrationBuilder.DropColumn( 33 | name: "Simplified", 34 | table: "Chars"); 35 | 36 | migrationBuilder.DropColumn( 37 | name: "Traditional", 38 | table: "Chars"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230227074215_202302271541.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | #nullable disable 10 | 11 | namespace DbCreator.MySql.Migrations; 12 | 13 | [DbContext(typeof(ChineseDbContext))] 14 | [Migration("20230227074215_202302271541")] 15 | partial class _202302271541 16 | { 17 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 18 | { 19 | #pragma warning disable 612, 618 20 | modelBuilder 21 | .HasAnnotation("ProductVersion", "6.0.11") 22 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 23 | 24 | modelBuilder.Entity("Chinese.Data.Char", b => 25 | { 26 | b.Property("Unicode") 27 | .ValueGeneratedOnAdd() 28 | .HasColumnType("int"); 29 | 30 | b.Property("Character") 31 | .IsRequired() 32 | .HasColumnType("varchar(1)"); 33 | 34 | b.Property("DefaultPinyin") 35 | .HasMaxLength(64) 36 | .HasColumnType("varchar(64)"); 37 | 38 | b.Property("IsPolyphone") 39 | .HasColumnType("tinyint(1)"); 40 | 41 | b.Property("Pinyins") 42 | .HasMaxLength(64) 43 | .HasColumnType("varchar(64)"); 44 | 45 | b.Property("Sight") 46 | .HasColumnType("tinyint(1)"); 47 | 48 | b.Property("Simplified") 49 | .HasMaxLength(64) 50 | .HasColumnType("varchar(64)"); 51 | 52 | b.Property("Traditional") 53 | .HasMaxLength(64) 54 | .HasColumnType("varchar(64)"); 55 | 56 | b.Property("Types") 57 | .HasColumnType("int"); 58 | 59 | b.HasKey("Unicode"); 60 | 61 | b.ToTable("Chars"); 62 | }); 63 | 64 | modelBuilder.Entity("Chinese.Data.Word", b => 65 | { 66 | b.Property("Id") 67 | .ValueGeneratedOnAdd() 68 | .HasColumnType("char(36)"); 69 | 70 | b.Property("HashCode") 71 | .HasColumnType("int"); 72 | 73 | b.Property("Simplified") 74 | .HasMaxLength(64) 75 | .HasColumnType("varchar(64)"); 76 | 77 | b.Property("SimplifiedPinyin") 78 | .HasMaxLength(64) 79 | .HasColumnType("varchar(64)"); 80 | 81 | b.Property("Traditional") 82 | .HasMaxLength(64) 83 | .HasColumnType("varchar(64)"); 84 | 85 | b.Property("TraditionalPinyin") 86 | .HasMaxLength(64) 87 | .HasColumnType("varchar(64)"); 88 | 89 | b.Property("Type") 90 | .HasColumnType("int"); 91 | 92 | b.HasKey("Id"); 93 | 94 | b.ToTable("Words"); 95 | }); 96 | #pragma warning restore 612, 618 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/20230227074215_202302271541.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #nullable disable 4 | 5 | namespace DbCreator.MySql.Migrations; 6 | 7 | public partial class _202302271541 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.DropTable( 12 | name: "Numerics"); 13 | 14 | migrationBuilder.AlterColumn( 15 | name: "TraditionalPinyin", 16 | table: "Words", 17 | type: "varchar(64)", 18 | maxLength: 64, 19 | nullable: true, 20 | oldClrType: typeof(string), 21 | oldType: "varchar(64)", 22 | oldMaxLength: 64) 23 | .Annotation("MySql:CharSet", "utf8mb4") 24 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 25 | 26 | migrationBuilder.AlterColumn( 27 | name: "Traditional", 28 | table: "Words", 29 | type: "varchar(64)", 30 | maxLength: 64, 31 | nullable: true, 32 | oldClrType: typeof(string), 33 | oldType: "varchar(64)", 34 | oldMaxLength: 64) 35 | .Annotation("MySql:CharSet", "utf8mb4") 36 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 37 | 38 | migrationBuilder.AlterColumn( 39 | name: "SimplifiedPinyin", 40 | table: "Words", 41 | type: "varchar(64)", 42 | maxLength: 64, 43 | nullable: true, 44 | oldClrType: typeof(string), 45 | oldType: "varchar(64)", 46 | oldMaxLength: 64) 47 | .Annotation("MySql:CharSet", "utf8mb4") 48 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 49 | 50 | migrationBuilder.AlterColumn( 51 | name: "Simplified", 52 | table: "Words", 53 | type: "varchar(64)", 54 | maxLength: 64, 55 | nullable: true, 56 | oldClrType: typeof(string), 57 | oldType: "varchar(64)", 58 | oldMaxLength: 64) 59 | .Annotation("MySql:CharSet", "utf8mb4") 60 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 61 | 62 | migrationBuilder.AlterColumn( 63 | name: "Traditional", 64 | table: "Chars", 65 | type: "varchar(64)", 66 | maxLength: 64, 67 | nullable: true, 68 | oldClrType: typeof(string), 69 | oldType: "varchar(64)", 70 | oldMaxLength: 64) 71 | .Annotation("MySql:CharSet", "utf8mb4") 72 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 73 | 74 | migrationBuilder.AlterColumn( 75 | name: "Simplified", 76 | table: "Chars", 77 | type: "varchar(64)", 78 | maxLength: 64, 79 | nullable: true, 80 | oldClrType: typeof(string), 81 | oldType: "varchar(64)", 82 | oldMaxLength: 64) 83 | .Annotation("MySql:CharSet", "utf8mb4") 84 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 85 | 86 | migrationBuilder.AlterColumn( 87 | name: "Pinyins", 88 | table: "Chars", 89 | type: "varchar(64)", 90 | maxLength: 64, 91 | nullable: true, 92 | oldClrType: typeof(string), 93 | oldType: "varchar(64)", 94 | oldMaxLength: 64) 95 | .Annotation("MySql:CharSet", "utf8mb4") 96 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 97 | 98 | migrationBuilder.AlterColumn( 99 | name: "DefaultPinyin", 100 | table: "Chars", 101 | type: "varchar(64)", 102 | maxLength: 64, 103 | nullable: true, 104 | oldClrType: typeof(string), 105 | oldType: "varchar(64)", 106 | oldMaxLength: 64) 107 | .Annotation("MySql:CharSet", "utf8mb4") 108 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 109 | } 110 | 111 | protected override void Down(MigrationBuilder migrationBuilder) 112 | { 113 | migrationBuilder.UpdateData( 114 | table: "Words", 115 | keyColumn: "TraditionalPinyin", 116 | keyValue: null, 117 | column: "TraditionalPinyin", 118 | value: ""); 119 | 120 | migrationBuilder.AlterColumn( 121 | name: "TraditionalPinyin", 122 | table: "Words", 123 | type: "varchar(64)", 124 | maxLength: 64, 125 | nullable: false, 126 | oldClrType: typeof(string), 127 | oldType: "varchar(64)", 128 | oldMaxLength: 64, 129 | oldNullable: true) 130 | .Annotation("MySql:CharSet", "utf8mb4") 131 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 132 | 133 | migrationBuilder.UpdateData( 134 | table: "Words", 135 | keyColumn: "Traditional", 136 | keyValue: null, 137 | column: "Traditional", 138 | value: ""); 139 | 140 | migrationBuilder.AlterColumn( 141 | name: "Traditional", 142 | table: "Words", 143 | type: "varchar(64)", 144 | maxLength: 64, 145 | nullable: false, 146 | oldClrType: typeof(string), 147 | oldType: "varchar(64)", 148 | oldMaxLength: 64, 149 | oldNullable: true) 150 | .Annotation("MySql:CharSet", "utf8mb4") 151 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 152 | 153 | migrationBuilder.UpdateData( 154 | table: "Words", 155 | keyColumn: "SimplifiedPinyin", 156 | keyValue: null, 157 | column: "SimplifiedPinyin", 158 | value: ""); 159 | 160 | migrationBuilder.AlterColumn( 161 | name: "SimplifiedPinyin", 162 | table: "Words", 163 | type: "varchar(64)", 164 | maxLength: 64, 165 | nullable: false, 166 | oldClrType: typeof(string), 167 | oldType: "varchar(64)", 168 | oldMaxLength: 64, 169 | oldNullable: true) 170 | .Annotation("MySql:CharSet", "utf8mb4") 171 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 172 | 173 | migrationBuilder.UpdateData( 174 | table: "Words", 175 | keyColumn: "Simplified", 176 | keyValue: null, 177 | column: "Simplified", 178 | value: ""); 179 | 180 | migrationBuilder.AlterColumn( 181 | name: "Simplified", 182 | table: "Words", 183 | type: "varchar(64)", 184 | maxLength: 64, 185 | nullable: false, 186 | oldClrType: typeof(string), 187 | oldType: "varchar(64)", 188 | oldMaxLength: 64, 189 | oldNullable: true) 190 | .Annotation("MySql:CharSet", "utf8mb4") 191 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 192 | 193 | migrationBuilder.UpdateData( 194 | table: "Chars", 195 | keyColumn: "Traditional", 196 | keyValue: null, 197 | column: "Traditional", 198 | value: ""); 199 | 200 | migrationBuilder.AlterColumn( 201 | name: "Traditional", 202 | table: "Chars", 203 | type: "varchar(64)", 204 | maxLength: 64, 205 | nullable: false, 206 | oldClrType: typeof(string), 207 | oldType: "varchar(64)", 208 | oldMaxLength: 64, 209 | oldNullable: true) 210 | .Annotation("MySql:CharSet", "utf8mb4") 211 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 212 | 213 | migrationBuilder.UpdateData( 214 | table: "Chars", 215 | keyColumn: "Simplified", 216 | keyValue: null, 217 | column: "Simplified", 218 | value: ""); 219 | 220 | migrationBuilder.AlterColumn( 221 | name: "Simplified", 222 | table: "Chars", 223 | type: "varchar(64)", 224 | maxLength: 64, 225 | nullable: false, 226 | oldClrType: typeof(string), 227 | oldType: "varchar(64)", 228 | oldMaxLength: 64, 229 | oldNullable: true) 230 | .Annotation("MySql:CharSet", "utf8mb4") 231 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 232 | 233 | migrationBuilder.UpdateData( 234 | table: "Chars", 235 | keyColumn: "Pinyins", 236 | keyValue: null, 237 | column: "Pinyins", 238 | value: ""); 239 | 240 | migrationBuilder.AlterColumn( 241 | name: "Pinyins", 242 | table: "Chars", 243 | type: "varchar(64)", 244 | maxLength: 64, 245 | nullable: false, 246 | oldClrType: typeof(string), 247 | oldType: "varchar(64)", 248 | oldMaxLength: 64, 249 | oldNullable: true) 250 | .Annotation("MySql:CharSet", "utf8mb4") 251 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 252 | 253 | migrationBuilder.UpdateData( 254 | table: "Chars", 255 | keyColumn: "DefaultPinyin", 256 | keyValue: null, 257 | column: "DefaultPinyin", 258 | value: ""); 259 | 260 | migrationBuilder.AlterColumn( 261 | name: "DefaultPinyin", 262 | table: "Chars", 263 | type: "varchar(64)", 264 | maxLength: 64, 265 | nullable: false, 266 | oldClrType: typeof(string), 267 | oldType: "varchar(64)", 268 | oldMaxLength: 64, 269 | oldNullable: true) 270 | .Annotation("MySql:CharSet", "utf8mb4") 271 | .OldAnnotation("MySql:CharSet", "utf8mb4"); 272 | 273 | migrationBuilder.CreateTable( 274 | name: "Numerics", 275 | columns: table => new 276 | { 277 | Id = table.Column(type: "char(36)", nullable: false, collation: "ascii_general_ci"), 278 | Simplified = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) 279 | .Annotation("MySql:CharSet", "utf8mb4"), 280 | SimplifiedPinyin = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) 281 | .Annotation("MySql:CharSet", "utf8mb4"), 282 | Traditional = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) 283 | .Annotation("MySql:CharSet", "utf8mb4"), 284 | TraditionalPinyin = table.Column(type: "varchar(64)", maxLength: 64, nullable: false) 285 | .Annotation("MySql:CharSet", "utf8mb4"), 286 | Type = table.Column(type: "int", nullable: false), 287 | Value = table.Column(type: "int", nullable: false) 288 | }, 289 | constraints: table => 290 | { 291 | table.PrimaryKey("PK_Numerics", x => x.Id); 292 | }) 293 | .Annotation("MySql:CharSet", "utf8mb4"); 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Migrations/ApplicationDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using Chinese.Data; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 7 | 8 | #nullable disable 9 | 10 | namespace DbCreator.MySql.Migrations; 11 | 12 | [DbContext(typeof(ChineseDbContext))] 13 | partial class ApplicationDbContextModelSnapshot : ModelSnapshot 14 | { 15 | protected override void BuildModel(ModelBuilder modelBuilder) 16 | { 17 | #pragma warning disable 612, 618 18 | modelBuilder 19 | .HasAnnotation("ProductVersion", "6.0.11") 20 | .HasAnnotation("Relational:MaxIdentifierLength", 64); 21 | 22 | modelBuilder.Entity("Chinese.Data.Char", b => 23 | { 24 | b.Property("Unicode") 25 | .ValueGeneratedOnAdd() 26 | .HasColumnType("int"); 27 | 28 | b.Property("Character") 29 | .IsRequired() 30 | .HasColumnType("varchar(1)"); 31 | 32 | b.Property("DefaultPinyin") 33 | .HasMaxLength(64) 34 | .HasColumnType("varchar(64)"); 35 | 36 | b.Property("IsPolyphone") 37 | .HasColumnType("tinyint(1)"); 38 | 39 | b.Property("Pinyins") 40 | .HasMaxLength(64) 41 | .HasColumnType("varchar(64)"); 42 | 43 | b.Property("Sight") 44 | .HasColumnType("tinyint(1)"); 45 | 46 | b.Property("Simplified") 47 | .HasMaxLength(64) 48 | .HasColumnType("varchar(64)"); 49 | 50 | b.Property("Traditional") 51 | .HasMaxLength(64) 52 | .HasColumnType("varchar(64)"); 53 | 54 | b.Property("Types") 55 | .HasColumnType("int"); 56 | 57 | b.HasKey("Unicode"); 58 | 59 | b.ToTable("Chars"); 60 | }); 61 | 62 | modelBuilder.Entity("Chinese.Data.Word", b => 63 | { 64 | b.Property("Id") 65 | .ValueGeneratedOnAdd() 66 | .HasColumnType("char(36)"); 67 | 68 | b.Property("HashCode") 69 | .HasColumnType("int"); 70 | 71 | b.Property("Simplified") 72 | .HasMaxLength(64) 73 | .HasColumnType("varchar(64)"); 74 | 75 | b.Property("SimplifiedPinyin") 76 | .HasMaxLength(64) 77 | .HasColumnType("varchar(64)"); 78 | 79 | b.Property("Traditional") 80 | .HasMaxLength(64) 81 | .HasColumnType("varchar(64)"); 82 | 83 | b.Property("TraditionalPinyin") 84 | .HasMaxLength(64) 85 | .HasColumnType("varchar(64)"); 86 | 87 | b.Property("Type") 88 | .HasColumnType("int"); 89 | 90 | b.HasKey("Id"); 91 | 92 | b.ToTable("Words"); 93 | }); 94 | #pragma warning restore 612, 618 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Tests/DbCreator.MySql/Program.cs: -------------------------------------------------------------------------------- 1 | using Chinese.Data; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace DbCreator; 5 | 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var sqliteOptions = new DbContextOptionsBuilder().UseSqlite("filename=chinese.db", null).Options; 11 | var mysqlConnectionString = "server=127.0.0.1;database=chinese"; 12 | var mysqlOptions = new DbContextOptionsBuilder().UseMySql(mysqlConnectionString, ServerVersion.AutoDetect(mysqlConnectionString), null).Options; 13 | 14 | using (var sqlite = new ChineseDbContext(sqliteOptions)) 15 | using (var mysql = new ChineseDbContext(mysqlOptions)) 16 | { 17 | sqlite.Database.Migrate(); 18 | } 19 | 20 | Console.WriteLine("Complete."); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /UPDATE_LOG.md: -------------------------------------------------------------------------------- 1 | # 更新日志 2 | 3 | ### Chars 4 | 5 | | | Unicode | 字符 | 简体字 | 繁体字 | 6 | | ---- | ------- | --------------------- | ------------- | ------ | 7 | | 更新 | 25222 | 抆 wěn wen | ~~擦~~ 抆 wěn | 抆 wěn | 8 | | 新增 | 32808 | 耨 nòu | 耨 nòu | 耨 nòu | 9 | | 更新 | 21633 | 咁 ~~han2~~ gān, xián | 咁 gān | 咁 gān | 10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /lib/netstandard2.0/ChineseConverter.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/Chinese/92a75fbdbc4f310257211256d557101544e32b3c/lib/netstandard2.0/ChineseConverter.dll -------------------------------------------------------------------------------- /lib/netstandard2.0/ChnCharInfo.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zmjack/Chinese/92a75fbdbc4f310257211256d557101544e32b3c/lib/netstandard2.0/ChnCharInfo.dll -------------------------------------------------------------------------------- /push.cmd: -------------------------------------------------------------------------------- 1 | nuget push "Chinese.Abstract/bin/Release/Chinese.Abstract.0.0.1.nupkg" -source nuget.org 2 | nuget push "Chinese/bin/Release/Chinese.0.8.1-alpha.nupkg" -source nuget.org 3 | pause 4 | --------------------------------------------------------------------------------