├── .github └── workflows │ └── sonarcloud.yml ├── .gitignore ├── LICENSE ├── README.md ├── doc ├── GB │ ├── GB11643-1999中华人民共和国第二代身份号码标准.pdf │ ├── GB11714-1997全国组织机构代码编制规则.pdf │ ├── GB32100-2015 法人和其他组织统一社会信用代码编码规则.pdf │ ├── GBT17710-2008 信息技术 安全技术 校验字符系统.pdf │ └── GBT2659-2000世界各国和地区名称代码.pdf └── 增值税发票 │ └── 全国增值税发票查询平台域名清单.doc └── src ├── NumberValidators.TestConsole ├── NumberValidators.TestConsole.csproj └── Program.cs ├── NumberValidators.Tests ├── AreaTests.cs ├── BusinessRegistrationNos │ ├── RegistrationNo15ValidatorTests.cs │ ├── RegistrationNo18ValidatorTests.cs │ └── RegistrationNoValidatorHelperTests.cs ├── IdentityCards │ ├── ID15ValidatorTests.cs │ ├── ID18ValidatorTests.cs │ └── IDValidatorHelperTests.cs ├── Invoices │ ├── VATCode10ValidatorTests.cs │ ├── VATCode12ValidatorTests.cs │ └── VATCodeValidatorHelperTests.cs ├── NumberValidators.Tests.csproj └── Utils │ ├── AreaHelperTests.cs │ ├── GBT11714_1997Tests.cs │ └── ISO7064_1983Tests.cs ├── NumberValidators.sln └── NumberValidators ├── Area.cs ├── AreaValidLimit.cs ├── BaseValidator.cs ├── BaseValidatorWithDictionary.cs ├── BusinessRegistrationNos ├── EnterpriseType.cs ├── ManagementCode.cs ├── ManagementKindCode.cs ├── RegistrationNoLength.cs ├── RegistrationNoValidationResult.cs └── Validators │ ├── ErrorMessage.cs │ ├── IRegistrationNoValidator.cs │ ├── RegistrationNo15ValidationResult.cs │ ├── RegistrationNo15Validator.cs │ ├── RegistrationNo18ValidationResult.cs │ ├── RegistrationNo18Validator.cs │ ├── RegistrationNoValidator.cs │ └── RegistrationNoValidatorHelper.cs ├── GlobalSuppressions.cs ├── IValidationDictionary.cs ├── IValidator.cs ├── IdentityCards ├── Gender.cs ├── IDLength.cs ├── IDValidationResult.cs └── Validators │ ├── ErrorMessage.cs │ ├── ID15Validator.cs │ ├── ID18Validator.cs │ ├── IDValidator.cs │ ├── IDValidatorHelper.cs │ └── IIDValidator.cs ├── Invoices ├── AmountVersion.cs ├── GBT2260OnlyProvince.cs ├── VATCodeValidationResult.cs ├── VATKind.cs ├── VATLength.cs └── Validators │ ├── ErrorMessage.cs │ ├── IVATCodeValidator.cs │ ├── VATCode10ValidationResult.cs │ ├── VATCode10Validator.cs │ ├── VATCode12ValidationResult.cs │ ├── VATCode12Validator.cs │ ├── VATCodeValidator.cs │ └── VATCodeValidatorHelper.cs ├── NumberValidators.csproj ├── Utils ├── AreaHelper.cs ├── GBT │ ├── GBT11714_1997.cs │ ├── GBT17710_1999.cs │ ├── GBT2260.cs │ ├── GBT2260_2013.cs │ ├── GBT2659_2000OfDigitalCode.cs │ └── NationCode.cs ├── ISO │ └── ISO7064_1983.cs ├── RandomHelper.cs ├── ReflectionHelper.cs ├── RegexPatterns.cs └── ValidatorHelper.cs └── ValidationResult.cs /.github/workflows/sonarcloud.yml: -------------------------------------------------------------------------------- 1 | name: sonarcloud 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: windows-2019 12 | steps: 13 | - name: Set up JDK 11 14 | uses: actions/setup-java@v1 15 | with: 16 | java-version: 1.11 17 | - uses: actions/checkout@v2 18 | with: 19 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 20 | - name: Setup .NET 21 | uses: actions/setup-dotnet@v1 22 | with: 23 | dotnet-version: 3.1.x 24 | - name: Restore dependencies 25 | run: dotnet restore .\src\NumberValidators.sln 26 | - name: Cache SonarCloud packages 27 | uses: actions/cache@v1 28 | with: 29 | path: ~\sonar\cache 30 | key: ${{ runner.os }}-sonar 31 | restore-keys: ${{ runner.os }}-sonar 32 | - name: Cache SonarCloud scanner 33 | id: cache-sonar-scanner 34 | uses: actions/cache@v1 35 | with: 36 | path: .\.sonar\scanner 37 | key: ${{ runner.os }}-sonar-scanner 38 | restore-keys: ${{ runner.os }}-sonar-scanner 39 | - name: Install SonarCloud scanner 40 | if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' 41 | shell: powershell 42 | run: | 43 | New-Item -Path .\.sonar\scanner -ItemType Directory 44 | dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner 45 | dotnet tool install coverlet.console -g 46 | - name: Build and analyze 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 49 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 50 | shell: powershell 51 | run: | 52 | .\.sonar\scanner\dotnet-sonarscanner begin /k:"fdstar_NumberValidators" /o:"fdstar" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths=".\src\TestResults\coverage.netcoreapp3.1.opencover.xml" 53 | dotnet build .\src\NumberValidators.sln --no-restore 54 | dotnet test .\src\NumberValidators.sln /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:Exclude="[xunit*]\*" /p:CoverletOutput="../TestResults/" 55 | .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/.vs 2 | /src/*/bin 3 | /src/*/obj 4 | /src/TestResults -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 fdstar 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NumberValidators 2 | 中国大陆证件、号码的验证类库,目前包含身份证、增值税发票、工商注册码/统一社会信用代码 3 | 4 | [![NuGet version (NumberValidators)](https://img.shields.io/nuget/v/NumberValidators.svg?style=flat-square)](https://www.nuget.org/packages/NumberValidators/) 5 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://mit-license.org/) 6 | 7 | ## .NET版本支持 8 | 目前支持以下版本:`.NET40`、`.NET Standard 2.0` 9 | 10 | ## 规范约束`IValidator` 11 | 所有验证均需实现`IValidator`接口,其中泛型`T`具备如下约束:必须继承自`ValidationResult`且需有无参构造函数,该接口定义了以下规范: 12 | * 随机生成一个符合规则的号码 `string GenerateRandomNumber();` 13 | * 验证号码是否正确 `T Validate(string number);` 14 | 15 | 实际验证会在此接口基础上定义额外的规范约束,且每种证件号码均默认提供`ValidatorHelper`类,用于统一验证该类型的证件号码,根据实际调用的`IValidator`实现,返回的`ValidationResult`也可能会有所不同,所有`Helper`类都提供了`AddDefaultValidator`来解决`Net Core`下反射生成实例会产生异常问题。 16 | 17 | PS:如果验证结果`IsValid`为True,那么相应的`ValidationResult`会包含该号码可识别的所有信息,以身份证为例,返回结果会包含**行政区划(即出生登记地)、出生日期、登记序列号、校验位** 18 | 19 | ## 简单的使用示例 20 | ### 1、大陆居民身份证 21 | 默认提供`ID15Validator`(15位一代身份证)以及`ID18Validator`(18位二代身份证)两种类型的身份证验证,具体使用代码如下: 22 | ```csharp 23 | //一代身份证验证,虽然目前未过期的一代身份证(未办理二代,如果办理了,有效期内的一代也就失效了)的仍然有效,但很多地方使用上已不被承认 24 | valid = new ID15Validator().Validate(idNumber); 25 | //二代身份证验证 26 | valid = new ID18Validator().Validate(idNumber); 27 | IDValidatorHelper.AddDefaultValidator(); //进行默认注册 28 | valid = IDValidatorHelper.Validate(idNumber, ignoreCheckBit: false); //无法确认是哪种身份证时可以通过该类进行验证 29 | ``` 30 | 31 | ### 2、增值税发票 32 | 默认提供`VATCode10Validator`(增值税专用发票、增值税普通发票、货物运输业增值税专用发票)以及`VATCode12Validator`(增值税普通发票[卷票]、增值税电子普通发票、区块链发票、增值税电子专用发票)两种长度的增值税发票验证(货物运输业增值税专用发票按国家规定目前已停用),具体使用代码如下: 33 | ```csharp 34 | valid = new VATCode10Validator().Validate(vatCode); //增值税专用发票、增值税普通发票、货物运输业增值税专用发票验证 35 | valid = new VATCode12Validator().Validate(vatCode); //增值税普通发票[卷票]、增值税电子普通发票验证 36 | valid = VATCodeValidatorHelper.Validate(vatCode, minYear: 2012); //无法确认是哪种增值税发票时可以通过该类进行验证 37 | ``` 38 | 注意`VATCode10Validator`返回验证结果为`VATCode10ValidationResult`,`VATCode12Validator`返回验证结果为`VATCode12ValidationResult`,`VATCodeValidatorHelper`返回验证结果为`VATCodeValidationResult`(实际也可能为`VATCode10ValidationResult`或`VATCode12ValidationResult`) 39 | 40 | ### 3、工商注册码/统一社会信用代码 41 | 默认提供`RegistrationNo15Validator`(工商注册码)以及`RegistrationNo18Validator`(法人和其他组织统一社会信用代码),具体使用代码如下: 42 | ```csharp 43 | valid = new RegistrationNo15Validator().Validate(code); //工商注册码验证 44 | valid = new RegistrationNo18Validator().Validate(code); //法人和其他组织统一社会信用代码验证 45 | valid = RegistrationNoValidatorHelper.Validate(code, validLimit: null); //无法确认是工商注册码还是法人和其他组织统一社会信用代码时可以通过该类进行验证 46 | ``` 47 | 注意`RegistrationNo15Validator`返回验证结果为`RegistrationNo15ValidationResult`,`RegistrationNo18Validator`返回验证结果为`RegistrationNo18ValidationResult`,`RegistrationNoValidatorHelper`返回验证结果为`RegistrationNoValidationResult`(实际也可能为`RegistrationNo15ValidationResult`或`RegistrationNo18ValidationResult`) 48 | 49 | 50 | ## Release History 51 | **2021-04-14** 52 | - Release v1.0.3 增加电子专票支持,Helper增加注册方法临时处理Core下反射生成实例失败问题 53 | 54 | **2019-08-06** 55 | - Release v1.0.2 增加区块链电子发票支持 56 | 57 | **2019-08-05** 58 | - Release v1.0.1 增加12位增值税普通发票支持,增加支持增值税电子发票通行费支持 59 | 60 | **2018-05-09** 61 | - Release v1.0.0 62 | -------------------------------------------------------------------------------- /doc/GB/GB11643-1999中华人民共和国第二代身份号码标准.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/GB/GB11643-1999中华人民共和国第二代身份号码标准.pdf -------------------------------------------------------------------------------- /doc/GB/GB11714-1997全国组织机构代码编制规则.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/GB/GB11714-1997全国组织机构代码编制规则.pdf -------------------------------------------------------------------------------- /doc/GB/GB32100-2015 法人和其他组织统一社会信用代码编码规则.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/GB/GB32100-2015 法人和其他组织统一社会信用代码编码规则.pdf -------------------------------------------------------------------------------- /doc/GB/GBT17710-2008 信息技术 安全技术 校验字符系统.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/GB/GBT17710-2008 信息技术 安全技术 校验字符系统.pdf -------------------------------------------------------------------------------- /doc/GB/GBT2659-2000世界各国和地区名称代码.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/GB/GBT2659-2000世界各国和地区名称代码.pdf -------------------------------------------------------------------------------- /doc/增值税发票/全国增值税发票查询平台域名清单.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fdstar/NumberValidators/6e29ac7a60a88cabee6fc03a24bb2467a7973978/doc/增值税发票/全国增值税发票查询平台域名清单.doc -------------------------------------------------------------------------------- /src/NumberValidators.TestConsole/NumberValidators.TestConsole.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/NumberValidators.TestConsole/Program.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.BusinessRegistrationNos.Validators; 2 | using NumberValidators.IdentityCards.Validators; 3 | using NumberValidators.Invoices.Validators; 4 | using System; 5 | 6 | namespace NumberValidators.TestConsole 7 | { 8 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Major Code Smell", "S1118:Utility classes should not have public constructors", Justification = "<挂起>")] 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | Console.WriteLine("Hello World!"); 14 | 15 | Console.WriteLine("***身份证***"); 16 | var id18Validator = new ID18Validator(); 17 | Console.WriteLine("随机的新身份证:" + id18Validator.GenerateRandomNumber()); 18 | var id15Validator = new ID15Validator(); 19 | Console.WriteLine("随机的旧身份证:" + id15Validator.GenerateRandomNumber()); 20 | #if DEBUG 21 | IDValidatorHelper.ResetDefaultValidator(); 22 | #endif 23 | 24 | var idValid = IDValidatorHelper.Validate("32021919900101003X", ignoreCheckBit: false); 25 | Console.WriteLine("身份证验证结果:" + idValid.IsValid); 26 | 27 | Console.WriteLine(); 28 | Console.WriteLine("***增值税发票***"); 29 | var vat10Validator = new VATCode10Validator(); 30 | var vat12Validator = new VATCode12Validator(); 31 | Console.WriteLine("随机的增值税发票:" + vat10Validator.GenerateRandomNumber()); 32 | Console.WriteLine("生成指定的增值税专用发票:" + vat10Validator.GenerateVATCode(3700, 2017, 1, Invoices.VATKind.Special)); 33 | Console.WriteLine("生成指定的10位增值税普通发票:" + vat10Validator.GenerateVATCode(1100, 2017, 2, Invoices.VATKind.Plain)); 34 | Console.WriteLine("生成指定的12位增值税普通发票:" + vat12Validator.GenerateVATCode(1100, 2018, 6, Invoices.VATKind.Plain)); 35 | Console.WriteLine("随机的增值税电子/卷票/普票:" + vat12Validator.GenerateRandomNumber()); 36 | string[] vatArr = { "044031800311", "034181600111", "034161700111", "1234567890", "144131909110", "031001600311", "3100153130", "011001800304", "035001800112", "144031909110", "065002100313" }; 37 | foreach (var vat in vatArr) 38 | { 39 | var valid = VATCodeValidatorHelper.Validate(vat, minYear: 2012); 40 | if (valid.IsValid) 41 | { 42 | Console.WriteLine("{0}验证结果:{1} 类型{2} 行政区划名称({3}) 验证结果类型:{4}", vat, valid.IsValid, valid.Category, valid.AreaName, valid); 43 | if (valid.Category == Invoices.VATKind.Electronic) 44 | { 45 | Console.WriteLine("{0}对应的增值税电子发票细分类型为:{1}", vat, ((VATCode12ValidationResult)valid).ElectronicVATKind); 46 | } 47 | else if (valid.Category == Invoices.VATKind.Blockchain) 48 | { 49 | Console.WriteLine("{0}对应的区块链电子发票批次为:{1} 联次为:{2}", vat, ((VATCode12ValidationResult)valid).Batch, ((VATCode12ValidationResult)valid).DuplicateNumber); 50 | } 51 | } 52 | else 53 | { 54 | PrintError(valid); 55 | } 56 | } 57 | 58 | Console.WriteLine(); 59 | Console.WriteLine("***工商注册码/统一社会信用代码***"); 60 | string[] rnArr = { "110108000000016", "91320621MA1MRHG205" }; 61 | foreach (var rn in rnArr) 62 | { 63 | var valid = RegistrationNoValidatorHelper.Validate(rn, validLimit: null); 64 | Console.WriteLine("{0}验证结果:{1} 长度{2} 行政区划名称({3}) 验证结果类型:{4}", rn, valid.IsValid, valid.RegistrationNoLength, valid.RecognizableArea?.FullName, valid); 65 | } 66 | Console.WriteLine("随机的工商注册码:" + new RegistrationNo15Validator().GenerateRandomNumber()); 67 | Console.WriteLine("随机的统一社会信用代码:" + new RegistrationNo18Validator().GenerateRandomNumber()); 68 | Console.ReadLine(); 69 | } 70 | 71 | static void PrintError(ValidationResult valid) 72 | { 73 | if (!valid.IsValid) 74 | { 75 | var prevColor = Console.ForegroundColor; 76 | Console.ForegroundColor = ConsoleColor.Yellow; 77 | Console.WriteLine("{0}验证失败:错误信息:{1}", valid.Number, string.Join(",", valid.Errors)); 78 | Console.ForegroundColor = prevColor; 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/AreaTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests 7 | { 8 | public class AreaTests 9 | { 10 | [Fact] 11 | public void Octr_Error() 12 | { 13 | Assert.Throws(() => new Area(1234, null)); 14 | Assert.Throws(() => new Area(1, string.Empty)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/BusinessRegistrationNos/RegistrationNo15ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.BusinessRegistrationNos; 2 | using NumberValidators.BusinessRegistrationNos.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.BusinessRegistrationNos 7 | { 8 | public class RegistrationNo15ValidatorTests 9 | { 10 | private readonly RegistrationNo15Validator validator = new RegistrationNo15Validator(); 11 | 12 | [Fact] 13 | public void Default_Prop() 14 | { 15 | Assert.Equal(RegistrationNoLength.Fifteen, validator.RegistrationNoLength); 16 | validator.AdministrationDictionary = null; 17 | Assert.NotNull(validator.AdministrationDictionary); 18 | Assert.True(validator.AdministrationDictionary.GetDictionary().ContainsKey(100000)); 19 | } 20 | 21 | [Fact] 22 | public void GenerateRandomNumber_Length_Should_Equals_15() 23 | { 24 | var number = validator.GenerateRandomNumber(); 25 | Assert.Equal(15, number.Length); 26 | } 27 | 28 | [Fact] 29 | public void GenerateRegistrationNo_Length_Should_Equals_15() 30 | { 31 | var number = validator.GenerateRegistrationNo(310104, EnterpriseType.Foreign); 32 | Assert.Equal(15, number.Length); 33 | } 34 | 35 | [Theory] 36 | [InlineData("110108000000017")] 37 | [InlineData("191108000000014")] 38 | public void Validate_Error(string no) 39 | { 40 | var valid = (IValidator)validator; 41 | var result = valid.Validate(no); 42 | Assert.False(result.IsValid); 43 | Assert.Equal(no, result.Number); 44 | Assert.NotEmpty(result.Errors); 45 | result = validator.Validate(no, AreaValidLimit.City); 46 | Assert.False(result.IsValid); 47 | Assert.NotEmpty(result.Errors); 48 | } 49 | 50 | [Theory] 51 | [InlineData("110108000000016")] 52 | public void Validate_Correct(string no) 53 | { 54 | var result = validator.Validate(no); 55 | Assert.True(result.IsValid); 56 | Assert.Empty(result.Errors); 57 | Assert.NotNull(result.RecognizableArea); 58 | Assert.Equal(110108, result.AreaNumber); 59 | Assert.Equal(result.AreaNumber, result.RecognizableArea.Number); 60 | Assert.Equal(1, result.SequenceNumber); 61 | Assert.Equal('6', result.CheckBit); 62 | Assert.Equal(EnterpriseType.Domestic, result.EnterpriseType); 63 | Assert.Equal(RegistrationNoLength.Fifteen, result.RegistrationNoLength); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/BusinessRegistrationNos/RegistrationNo18ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.BusinessRegistrationNos; 2 | using NumberValidators.BusinessRegistrationNos.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.BusinessRegistrationNos 7 | { 8 | public class RegistrationNo18ValidatorTests 9 | { 10 | private readonly RegistrationNo18Validator validator = new RegistrationNo18Validator(); 11 | 12 | [Fact] 13 | public void Default_Prop() 14 | { 15 | Assert.Equal(RegistrationNoLength.Eighteen, validator.RegistrationNoLength); 16 | } 17 | 18 | [Fact] 19 | public void GenerateRandomNumber_Length_Should_Equals_18() 20 | { 21 | var number = validator.GenerateRandomNumber(); 22 | Assert.Equal(18, number.Length); 23 | } 24 | 25 | [Fact] 26 | public void GenerateRegistrationNo_Length_Should_Equals_18() 27 | { 28 | var number = validator.GenerateRegistrationNo(310104, ManagementCode.Business); 29 | Assert.Equal(18, number.Length); 30 | number = validator.GenerateRegistrationNo(310104, ManagementCode.Business, ManagementKindCode.Foundation); 31 | Assert.Equal(18, number.Length); 32 | } 33 | 34 | [Theory] 35 | [InlineData("91320621MA1MRHG207")] 36 | [InlineData("A1320621MA1MRHG217")] 37 | [InlineData("B7320621MA1MRHG20G")] 38 | [InlineData("L8320621MA1MRHG204")] 39 | public void Validate_Error(string no) 40 | { 41 | var valid = (IValidator)validator; 42 | var result = valid.Validate(no); 43 | Assert.False(result.IsValid); 44 | Assert.Equal(no, result.Number); 45 | Assert.NotEmpty(result.Errors); 46 | } 47 | 48 | [Theory] 49 | [InlineData("91320621MA1MRHG205")] 50 | public void Validate_Correct(string no) 51 | { 52 | var result = validator.Validate(no); 53 | Assert.True(result.IsValid); 54 | Assert.Empty(result.Errors); 55 | Assert.NotNull(result.RecognizableArea); 56 | Assert.Equal(ManagementCode.Business, result.ManagementCode); 57 | Assert.Equal(ManagementKindCode.Enterprise, result.ManagementKindCode); 58 | Assert.Equal(320621, result.AreaNumber); 59 | Assert.Equal(result.AreaNumber, result.RecognizableArea.Number); 60 | Assert.Equal("MA1MRHG20", result.OrganizationCode); 61 | Assert.Equal('5', result.CheckBit); 62 | Assert.Equal(RegistrationNoLength.Eighteen, result.RegistrationNoLength); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/BusinessRegistrationNos/RegistrationNoValidatorHelperTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.BusinessRegistrationNos; 2 | using NumberValidators.BusinessRegistrationNos.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.BusinessRegistrationNos 7 | { 8 | public class RegistrationNoValidatorHelperTests 9 | { 10 | [Theory] 11 | [InlineData((string)null)] 12 | [InlineData("123456789")] 13 | public void Valid_No_Is_Empty_Or_Not_Supported_Length(string no) 14 | { 15 | var result = RegistrationNoValidatorHelper.Validate(no, 9); 16 | Assert.IsType(result); 17 | Assert.False(result.IsValid); 18 | } 19 | 20 | [Theory] 21 | [InlineData("450703583197518")] 22 | [InlineData("440783763666398")] 23 | public void Valid_Correct_With_Length_15(string no) 24 | { 25 | var result = RegistrationNoValidatorHelper.Validate(no); 26 | Assert.IsType(result); 27 | Assert.True(result.IsValid); 28 | var ret = (RegistrationNo15ValidationResult)result; 29 | Assert.True(ret.EnterpriseType > EnterpriseType.Domestic); 30 | } 31 | 32 | [Theory] 33 | [InlineData("91320621MA1MRHG205")] 34 | public void Valid_Correct_With_Length_18(string no) 35 | { 36 | var result = RegistrationNoValidatorHelper.Validate(no); 37 | Assert.IsType(result); 38 | Assert.True(result.IsValid); 39 | } 40 | 41 | [Theory] 42 | [InlineData("110108000000016")] 43 | public void Set_Another_Validator_To_Replace_15_And_Reset(string no) 44 | { 45 | Assert.Throws(() => RegistrationNoValidatorHelper.SetValidator((int)RegistrationNoLength.Fifteen, null)); 46 | RegistrationNoValidatorHelper.SetValidator((int)RegistrationNoLength.Fifteen, new NotImplementedRegistrationNo15Validator()); 47 | Assert.Throws(() => RegistrationNoValidatorHelper.Validate(no)); 48 | RegistrationNoValidatorHelper.ResetDefaultValidator(); 49 | Assert.True(RegistrationNoValidatorHelper.Validate(no).IsValid); 50 | } 51 | } 52 | 53 | internal sealed class NotImplementedRegistrationNo15Validator : IRegistrationNoValidator 54 | { 55 | public IValidationDictionary Dictionary { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 56 | 57 | public RegistrationNoLength RegistrationNoLength => throw new NotImplementedException(); 58 | 59 | public string GenerateRandomNumber() 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | 64 | public RegistrationNoValidationResult Validate(string code, AreaValidLimit? validLimit = null) 65 | { 66 | throw new NotImplementedException(); 67 | } 68 | 69 | public RegistrationNoValidationResult Validate(string number) 70 | { 71 | throw new NotImplementedException(); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/IdentityCards/ID15ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.IdentityCards; 2 | using NumberValidators.IdentityCards.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.IdentityCards 7 | { 8 | public class ID15ValidatorTests 9 | { 10 | private readonly IDValidator validator = new ID15Validator(); 11 | 12 | [Fact] 13 | public void Default_Prop() 14 | { 15 | Assert.Equal(IDLength.Fifteen, validator.IDLength); 16 | } 17 | 18 | [Fact] 19 | public void GenerateRandomNumber_Length_Should_Equals_15() 20 | { 21 | var number = validator.GenerateRandomNumber(); 22 | Assert.Equal(15, number.Length); 23 | } 24 | 25 | [Fact] 26 | public void GenerateID_Length_Should_Equals_15() 27 | { 28 | var number = validator.GenerateID(310104, new DateTime(2000, 1, 1), 7); 29 | Assert.Equal(15, number.Length); 30 | } 31 | [Fact] 32 | public void GenerateID_ArgumentException() 33 | { 34 | Assert.Throws(()=> validator.GenerateID(5, new DateTime(2000, 1, 1), 7)); 35 | Assert.Throws(() => validator.GenerateID(310104, new DateTime(2000, 1, 1), 9999)); 36 | } 37 | 38 | [Theory] 39 | [InlineData("954321700422319")] 40 | [InlineData("100000700422319")] 41 | public void Validate_Error(string no) 42 | { 43 | var valid = (IValidator)validator; 44 | var result = valid.Validate(no); 45 | Assert.False(result.IsValid); 46 | Assert.Equal(no, result.Number); 47 | Assert.NotEmpty(result.Errors); 48 | } 49 | 50 | [Theory] 51 | [InlineData("411702700422319")] 52 | public void Validate_Correct(string no) 53 | { 54 | var result = validator.Validate(no); 55 | Assert.True(result.IsValid); 56 | Assert.Empty(result.Errors); 57 | Assert.NotNull(result.RecognizableArea); 58 | Assert.Equal(IDLength.Fifteen, result.IDLength); 59 | Assert.Equal(new DateTime(1970, 4, 22), result.Birthday); 60 | Assert.Equal(Gender.Male, result.Gender); 61 | Assert.Equal(411702, result.AreaNumber); 62 | Assert.Equal(result.AreaNumber, result.RecognizableArea.Number); 63 | Assert.Equal(319, result.Sequence); 64 | Assert.Equal(char.MinValue, result.CheckBit); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/IdentityCards/ID18ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.IdentityCards; 2 | using NumberValidators.IdentityCards.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.IdentityCards 7 | { 8 | public class ID18ValidatorTests 9 | { 10 | private readonly IDValidator validator = new ID18Validator(); 11 | 12 | [Fact] 13 | public void Default_Prop() 14 | { 15 | Assert.Equal(IDLength.Eighteen, validator.IDLength); 16 | } 17 | 18 | [Fact] 19 | public void GenerateRandomNumber_Length_Should_Equals_18() 20 | { 21 | var number = validator.GenerateRandomNumber(); 22 | Assert.Equal(18, number.Length); 23 | } 24 | 25 | [Fact] 26 | public void GenerateID_Length_Should_Equals_18() 27 | { 28 | var number = validator.GenerateID(310104, new DateTime(2000, 1, 1), 7); 29 | Assert.Equal(18, number.Length); 30 | } 31 | [Fact] 32 | public void GenerateID_ArgumentException() 33 | { 34 | Assert.Throws(() => validator.GenerateID(5, new DateTime(2000, 1, 1), 7)); 35 | Assert.Throws(() => validator.GenerateID(310104, new DateTime(2000, 1, 1), 9999)); 36 | } 37 | 38 | [Theory] 39 | [InlineData("32021919900101003X")] 40 | [InlineData("320281198501010036")] 41 | [InlineData("320281000101010036")] 42 | [InlineData("32028119950101003X")] 43 | public void Validate_Error(string no) 44 | { 45 | var result = validator.Validate(no, 1990, AreaValidLimit.County); 46 | Assert.False(result.IsValid); 47 | Assert.Equal(no, result.Number); 48 | Assert.NotEmpty(result.Errors); 49 | } 50 | 51 | [Theory] 52 | [InlineData("32021919900101003X")] 53 | public void Validate_Correct(string no) 54 | { 55 | var result = validator.Validate(no); 56 | Assert.True(result.IsValid); 57 | Assert.Empty(result.Errors); 58 | Assert.NotNull(result.RecognizableArea); 59 | Assert.Equal(IDLength.Eighteen, result.IDLength); 60 | Assert.Equal(new DateTime(1990, 1, 1), result.Birthday); 61 | Assert.Equal(Gender.Male, result.Gender); 62 | Assert.Equal(320219, result.AreaNumber); 63 | Assert.Equal(003, result.Sequence); 64 | Assert.Equal('X', result.CheckBit); 65 | Assert.Equal("江苏省无锡市", result.RecognizableArea.FullName); 66 | Assert.Equal("江苏省", result.RecognizableArea.Parent.Name); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/IdentityCards/IDValidatorHelperTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.IdentityCards; 2 | using NumberValidators.IdentityCards.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests.IdentityCards 7 | { 8 | public class IDValidatorHelperTests 9 | { 10 | [Theory] 11 | [InlineData((string)null)] 12 | [InlineData("123456789")] 13 | public void Valid_No_Is_Empty_Or_Not_Supported_Length(string no) 14 | { 15 | var result = IDValidatorHelper.Validate(no, 9); 16 | Assert.False(result.IsValid); 17 | } 18 | 19 | [Theory] 20 | [InlineData("411702700422319")] 21 | public void TryPromotion_Correct(string no) 22 | { 23 | Assert.True(IDValidatorHelper.TryPromotion(no, out string newID)); 24 | Assert.Equal("41170219700422319X", newID); 25 | } 26 | 27 | [Theory] 28 | [InlineData("965432700422319")] 29 | public void TryPromotion_Error(string no) 30 | { 31 | Assert.False(IDValidatorHelper.TryPromotion(no, out string newID)); 32 | Assert.Null(newID); 33 | } 34 | 35 | [Theory] 36 | [InlineData("411702700422319")] 37 | [InlineData("32021919900101003X")] 38 | public void Valid_Correct(string no) 39 | { 40 | var result = IDValidatorHelper.Validate(no); 41 | Assert.True(result.IsValid); 42 | } 43 | 44 | [Theory] 45 | [InlineData("411702700422319")] 46 | public void Set_Another_Validator_To_Replace_15_And_Reset(string no) 47 | { 48 | Assert.Throws(() => IDValidatorHelper.SetValidator((int)IDLength.Fifteen, null)); 49 | IDValidatorHelper.SetValidator((int)IDLength.Fifteen, new NotImplementedIDValidator()); 50 | Assert.Throws(() => IDValidatorHelper.Validate(no)); 51 | IDValidatorHelper.ResetDefaultValidator(); 52 | Assert.True(IDValidatorHelper.Validate(no).IsValid); 53 | } 54 | } 55 | internal sealed class NotImplementedIDValidator : IIDValidator 56 | { 57 | public IValidationDictionary Dictionary { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 58 | 59 | public string GenerateID(int areaNumber, DateTime birthDay, int sequenceNumber) 60 | { 61 | throw new NotImplementedException(); 62 | } 63 | 64 | public string GenerateRandomNumber() 65 | { 66 | throw new NotImplementedException(); 67 | } 68 | 69 | public IDValidationResult Validate(string idNumber, ushort minYear = 0, AreaValidLimit validLimit = AreaValidLimit.Province, bool ignoreCheckBit = false) 70 | { 71 | throw new NotImplementedException(); 72 | } 73 | 74 | public IDValidationResult Validate(string number) 75 | { 76 | throw new NotImplementedException(); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Invoices/VATCode10ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Invoices; 2 | using NumberValidators.Invoices.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests 7 | { 8 | public class VATCode10ValidatorTests 9 | { 10 | private readonly VATCode10Validator validator = new VATCode10Validator(); 11 | 12 | [Fact] 13 | public void GenerateRandomNumber_Length_Should_Equals_10() 14 | { 15 | var number = validator.GenerateRandomNumber(); 16 | Assert.Equal(10, number.Length); 17 | } 18 | 19 | [Fact] 20 | public void GenerateVATCode_Length_Should_Equals_10() 21 | { 22 | var number = validator.GenerateVATCode(3100, 2020, 1, VATKind.Special); 23 | Assert.Equal(10, number.Length); 24 | } 25 | [Fact] 26 | public void GenerateVATCode_Exception() 27 | { 28 | Assert.Throws(() => validator.GenerateVATCode(5, 2020, 1, VATKind.Special)); 29 | Assert.Throws(() => validator.GenerateVATCode(3100, 2020, 1, VATKind.Blockchain)); 30 | } 31 | 32 | [Theory] 33 | [InlineData("3100203130")] 34 | [InlineData("3120203130")] 35 | [InlineData("1100172320")] 36 | public void Validate_Error(string no) 37 | { 38 | var result = validator.Validate(no, VATKind.Plain, 2018); 39 | Assert.False(result.IsValid); 40 | Assert.Equal(no, result.Number); 41 | Assert.NotEmpty(result.Errors); 42 | } 43 | 44 | [Theory] 45 | [InlineData("3100153130")] 46 | public void Validate_Correct(string no) 47 | { 48 | var result = validator.Validate(no); 49 | Assert.True(result.IsValid); 50 | Assert.Empty(result.Errors); 51 | Assert.Equal(VATLength.Ten, result.VATLength); 52 | Assert.Equal(3100, result.AreaNumber); 53 | Assert.Equal("上海市", result.AreaName); 54 | Assert.Equal(VATKind.Special, result.Category); 55 | Assert.Equal(2015, result.Year); 56 | Assert.Equal(1, result.Batch); 57 | Assert.Equal(3, result.DuplicateNumber); 58 | Assert.Equal(AmountVersion.Computer, result.AmountVersion); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Invoices/VATCode12ValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Invoices; 2 | using NumberValidators.Invoices.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests 7 | { 8 | public class VATCode12ValidatorTests 9 | { 10 | private readonly VATCode12Validator validator = new VATCode12Validator(); 11 | 12 | [Fact] 13 | public void GenerateRandomNumber_Length_Should_Equals_12() 14 | { 15 | var number = validator.GenerateRandomNumber(); 16 | Assert.Equal(12, number.Length); 17 | } 18 | 19 | [Fact] 20 | public void GenerateVATCode_Length_Should_Equals_12() 21 | { 22 | var number = validator.GenerateVATCode(3100, 2020, 1, VATKind.Electronic, ElectronicVATKind.Normal); 23 | Assert.Equal(12, number.Length); 24 | } 25 | [Fact] 26 | public void GenerateVATCode_Exception() 27 | { 28 | Assert.Throws(() => validator.GenerateVATCode(4403, 2020, 1, VATKind.Blockchain, ElectronicVATKind.Normal)); 29 | Assert.Throws(() => validator.GenerateVATCode(5, 2020, 1, VATKind.Electronic)); 30 | Assert.Throws(() => validator.GenerateVATCode(3100, 2020, 1, VATKind.Transport)); 31 | } 32 | 33 | [Theory] 34 | [InlineData("12345")] 35 | [InlineData("011001800304")] 36 | [InlineData("035001800112")] 37 | [InlineData("054002000314")] 38 | [InlineData("144052009110")] 39 | [InlineData("144032009111")] 40 | public void Validate_Error(string no) 41 | { 42 | var result = validator.Validate(no, minYear: 2020); 43 | Assert.False(result.IsValid); 44 | Assert.Equal(no, result.Number); 45 | Assert.NotEmpty(result.Errors); 46 | } 47 | 48 | [Theory] 49 | [InlineData("065122100313")] 50 | public void Validate_Correct_With_Electronic(string no) 51 | { 52 | var result = validator.Validate(no); 53 | Assert.True(result.IsValid); 54 | Assert.Empty(result.Errors); 55 | Assert.Equal(VATLength.Twelve, result.VATLength); 56 | Assert.Equal(6512, result.AreaNumber); 57 | Assert.Equal("新疆维吾尔自治区", result.AreaName); 58 | Assert.Equal(VATKind.Electronic, result.Category); 59 | Assert.Equal(2021, result.Year); 60 | Assert.Equal(3, result.Batch); 61 | Assert.Equal(0, result.DuplicateNumber); 62 | Assert.Equal(ElectronicVATKind.Special, result.ElectronicVATKind); 63 | } 64 | 65 | [Theory] 66 | [InlineData("011001800604")] 67 | public void Validate_Correct_With_Plain(string no) 68 | { 69 | var result = validator.Validate(no); 70 | Assert.True(result.IsValid); 71 | Assert.Empty(result.Errors); 72 | Assert.Equal(VATLength.Twelve, result.VATLength); 73 | Assert.Equal(VATKind.Plain, result.Category); 74 | Assert.Equal(2018, result.Year); 75 | Assert.Equal(6, result.Batch); 76 | Assert.Equal(2, result.DuplicateNumber); 77 | Assert.Null(result.ElectronicVATKind); 78 | } 79 | 80 | [Theory] 81 | [InlineData("144031909110")] 82 | public void Validate_Correct_With_Blockchain(string no) 83 | { 84 | var result = ((IValidator)validator).Validate(no); 85 | Assert.True(result.IsValid); 86 | Assert.Equal(VATKind.Blockchain, result.Category); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Invoices/VATCodeValidatorHelperTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Invoices; 2 | using NumberValidators.Invoices.Validators; 3 | using System; 4 | using Xunit; 5 | 6 | namespace NumberValidators.Tests 7 | { 8 | public class VATCodeValidatorHelperTests 9 | { 10 | 11 | [Theory] 12 | [InlineData((string)null)] 13 | [InlineData("123456789")] 14 | public void Valid_No_Is_Empty_Or_Not_Supported_Length(string no) 15 | { 16 | var result = VATCodeValidatorHelper.Validate(no, length: 9); 17 | Assert.IsType(result); 18 | Assert.False(result.IsValid); 19 | } 20 | 21 | [Theory] 22 | [InlineData("3100153130")] 23 | public void Valid_Correct_With_Length_10(string no) 24 | { 25 | var result = VATCodeValidatorHelper.Validate(no); 26 | Assert.IsType(result); 27 | Assert.True(result.IsValid); 28 | } 29 | 30 | [Theory] 31 | [InlineData("011001800604")] 32 | public void Valid_Correct_With_Length_12(string no) 33 | { 34 | var result = VATCodeValidatorHelper.Validate(no); 35 | Assert.IsType(result); 36 | Assert.True(result.IsValid); 37 | } 38 | 39 | [Theory] 40 | [InlineData("3100153130")] 41 | public void Set_Another_Validator_To_Replace_10_And_Reset(string no) 42 | { 43 | Assert.Throws(() => VATCodeValidatorHelper.SetValidator((int)VATLength.Ten, null)); 44 | VATCodeValidatorHelper.SetValidator((int)VATLength.Ten, new NotImplementedVATCodeValidator()); 45 | Assert.Throws(() => VATCodeValidatorHelper.Validate(no)); 46 | VATCodeValidatorHelper.ResetDefaultValidator(); 47 | Assert.True(VATCodeValidatorHelper.Validate(no).IsValid); 48 | } 49 | } 50 | 51 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>")] 52 | internal sealed class NotImplementedVATCodeValidator : IVATCodeValidator 53 | { 54 | public IValidationDictionary Dictionary { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } 55 | 56 | public string GenerateRandomNumber() 57 | { 58 | throw new NotImplementedException(); 59 | } 60 | 61 | public string GenerateVATCode(int areaNumber, ushort year, ushort batch, VATKind kind, ElectronicVATKind? electKind = null) 62 | { 63 | throw new NotImplementedException(); 64 | } 65 | 66 | public VATCodeValidationResult Validate(string vatCode, VATKind? kind = null, ushort minYear = 2012) 67 | { 68 | throw new NotImplementedException(); 69 | } 70 | 71 | public VATCodeValidationResult Validate(string number) 72 | { 73 | throw new NotImplementedException(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/NumberValidators.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1;net452 5 | 6 | false 7 | 8 | 9 | 10 | 11 | all 12 | runtime; build; native; contentfiles; analyzers; buildtransitive 13 | 14 | 15 | 16 | 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | all 19 | 20 | 21 | runtime; build; native; contentfiles; analyzers; buildtransitive 22 | all 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Utils/AreaHelperTests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Xunit; 7 | 8 | namespace NumberValidators.Tests.Utils 9 | { 10 | public class AreaHelperTests 11 | { 12 | [Fact] 13 | public void GetDeepestArea_Error() 14 | { 15 | Assert.Throws(() => AreaHelper.GetDeepestArea(10, null)); 16 | Assert.Throws(() => AreaHelper.GetDeepestArea(1, GBT2260_2013.Singleton)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Utils/GBT11714_1997Tests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using Xunit; 7 | 8 | namespace NumberValidators.Tests.Utils 9 | { 10 | public class GBT11714_1997Tests 11 | { 12 | [Fact] 13 | public void GetCheckBit_Error() 14 | { 15 | Assert.Throws(() => GBT11714_1997.GetCheckBit(null)); 16 | Assert.Throws(() => GBT11714_1997.GetCheckBit("12345")); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/NumberValidators.Tests/Utils/ISO7064_1983Tests.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils.ISO; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using Xunit; 6 | 7 | namespace NumberValidators.Tests.Utils 8 | { 9 | public class ISO7064_1983Tests 10 | { 11 | [Fact] 12 | public void MOD_11_2_Error() 13 | { 14 | Assert.Throws(() => ISO7064_1983.MOD_11_2(null, null, 10)); 15 | Assert.Throws(() => ISO7064_1983.MOD_11_2(new int[] { 1, 2 }, null, 10)); 16 | Assert.Throws(() => ISO7064_1983.MOD_11_2(new int[] { 1, 2 }, new int[] { 1, 2, 3 }, 10)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/NumberValidators.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31911.196 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NumberValidators", "NumberValidators\NumberValidators.csproj", "{26FF2557-EA50-4045-B040-076082FD7F45}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NumberValidators.TestConsole", "NumberValidators.TestConsole\NumberValidators.TestConsole.csproj", "{FD3DFF39-FA12-457D-9BD4-63C3BD04246A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NumberValidators.Tests", "NumberValidators.Tests\NumberValidators.Tests.csproj", "{49B15718-7C19-4CB8-9C26-348CD86CEFB5}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{E19AE3B9-2842-4533-AB21-E1EA377C9194}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{9E3F46DD-FC94-4319-BA11-2D562E9F9C74}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {26FF2557-EA50-4045-B040-076082FD7F45}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {26FF2557-EA50-4045-B040-076082FD7F45}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {26FF2557-EA50-4045-B040-076082FD7F45}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {26FF2557-EA50-4045-B040-076082FD7F45}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {FD3DFF39-FA12-457D-9BD4-63C3BD04246A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {FD3DFF39-FA12-457D-9BD4-63C3BD04246A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {FD3DFF39-FA12-457D-9BD4-63C3BD04246A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {FD3DFF39-FA12-457D-9BD4-63C3BD04246A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {49B15718-7C19-4CB8-9C26-348CD86CEFB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {49B15718-7C19-4CB8-9C26-348CD86CEFB5}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {49B15718-7C19-4CB8-9C26-348CD86CEFB5}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {49B15718-7C19-4CB8-9C26-348CD86CEFB5}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(NestedProjects) = preSolution 39 | {FD3DFF39-FA12-457D-9BD4-63C3BD04246A} = {9E3F46DD-FC94-4319-BA11-2D562E9F9C74} 40 | {49B15718-7C19-4CB8-9C26-348CD86CEFB5} = {E19AE3B9-2842-4533-AB21-E1EA377C9194} 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {9105D3CF-EB3C-4819-B25E-5B075D2D721A} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /src/NumberValidators/Area.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators 7 | { 8 | /// 9 | /// 行政区划 10 | /// 11 | public class Area 12 | { 13 | /// 14 | /// 行政区划构造函数 15 | /// 16 | /// 17 | /// 18 | public Area(int number, string name) 19 | { 20 | if (name == null || number.ToString().Length % 2 != 0) 21 | { 22 | throw new ArgumentException("The number or name is not correct!"); 23 | } 24 | this.Number = number; 25 | this.Name = name.Trim(); 26 | } 27 | /// 28 | /// 行政区划代码 29 | /// 30 | public int Number { get; } 31 | /// 32 | /// 行政区域名称(仅当前节点) 33 | /// 34 | public string Name { get; } 35 | /// 36 | /// 行政区域完整名称(包含上级行政区域名称) 37 | /// 38 | public string FullName 39 | { 40 | get 41 | { 42 | StringBuilder tmp = new StringBuilder(); 43 | var area = this; 44 | while (area != null) 45 | { 46 | tmp.Insert(0, area.Name); 47 | area = area.Parent; 48 | } 49 | return tmp.ToString(); 50 | } 51 | } 52 | /// 53 | /// 父级区域 54 | /// 55 | /// 56 | public Area Parent { get; internal set; } 57 | 58 | /// 59 | /// 获取当前区域的深度,从1开始,按照GB2260行政区域编码规则2位为一个深度 60 | /// 61 | /// 62 | public int GetDepth() 63 | { 64 | return this.Number.ToString().Length / 2; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/NumberValidators/AreaValidLimit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators 7 | { 8 | /// 9 | /// 区域验证级别限制 10 | /// 11 | public enum AreaValidLimit 12 | { 13 | /// 14 | /// 省,即身份证号码的前两位,新中国建立以来行政区域列表还未对省级做过调整 15 | /// 16 | Province = 1, 17 | /// 18 | /// 市,即身份证号码的前四位,新中国建立以来对少数市级区域做过调整 19 | /// 20 | City = 2, 21 | /// 22 | /// 县,即身份证号码的前六位,县级调整是最频繁的 23 | /// 24 | County = 3 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/NumberValidators/BaseValidator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace NumberValidators 9 | { 10 | /// 11 | /// 基础验证类,默认包含了空验证和正则验证,提供默认的错误信息描述 12 | /// 13 | /// 14 | public abstract class BaseValidator : IValidator 15 | where T : ValidationResult, new() 16 | { 17 | /// 18 | /// 用于判断输入号码是否正确的正则表达式,如果不设定,则不进行正则匹配 19 | /// 20 | protected virtual string RegexPattern { get; } 21 | /// 22 | /// 号码为空时的错误信息 23 | /// 24 | protected virtual string EmptyErrorMessage { get; } = "号码不能为空"; 25 | /// 26 | /// 正则匹配失败时的错误信息 27 | /// 28 | protected virtual string RegexMatchFailMessage { get; } = "号码错误"; 29 | /// 30 | /// 生成随机号码 31 | /// 32 | /// 33 | public abstract string GenerateRandomNumber(); 34 | /// 35 | /// 验证号码是否正确 36 | /// 37 | /// 38 | /// 39 | public virtual T Validate(string number) 40 | { 41 | if (ValidatorHelper.ValidEmpty(number, out T result, EmptyErrorMessage)) 42 | { 43 | this.ValidWithPattern(number, result); 44 | } 45 | return result; 46 | } 47 | /// 48 | /// 按正则验证号码是否正确 49 | /// 50 | /// 51 | /// 52 | /// 53 | protected virtual bool ValidWithPattern(string number, T result) 54 | { 55 | bool valid = string.IsNullOrEmpty(this.RegexPattern)|| Regex.IsMatch(number, this.RegexPattern); 56 | if (!valid) 57 | { 58 | result.AddErrorMessage(this.RegexMatchFailMessage); 59 | } 60 | return valid; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/NumberValidators/BaseValidatorWithDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators 6 | { 7 | /// 8 | /// 基于数据字典的验证基类 9 | /// 10 | /// 验证结果类型 11 | /// 字典Key 12 | /// 字典Value 13 | public abstract class BaseValidatorWithDictionary : BaseValidator 14 | where TResult : ValidationResult, new() 15 | { 16 | private IValidationDictionary _dictionary; 17 | /// 18 | /// 默认字典类 19 | /// 20 | protected abstract IValidationDictionary DefaultDictionary { get; } 21 | /// 22 | /// 获取字典类 23 | /// 24 | public IValidationDictionary Dictionary 25 | { 26 | get 27 | { 28 | return this._dictionary ?? DefaultDictionary; 29 | } 30 | set 31 | { 32 | this._dictionary = value; 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/EnterpriseType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos 6 | { 7 | /// 8 | /// 企业类型 9 | /// 10 | public enum EnterpriseType 11 | { 12 | /// 13 | /// 内资企业 0123 14 | /// 15 | Domestic = 3, 16 | /// 17 | /// 外资企业 45 18 | /// 19 | Foreign = 5, 20 | /// 21 | /// 个体工商户 6789 22 | /// 23 | Individual = 9 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/ManagementCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos 6 | { 7 | /// 8 | /// 登记管理部门代码标志,对应ASCII 9 | /// 10 | public enum ManagementCode 11 | { 12 | /// 13 | /// 机构编制 (1) 14 | /// 15 | Institution = 49, 16 | /// 17 | /// 外交 (2) 18 | /// 19 | Diplomacy = 50, 20 | /// 21 | /// 教育 (3) 22 | /// 23 | Education = 51, 24 | /// 25 | /// 公安 (4) 26 | /// 27 | Police = 52, 28 | /// 29 | /// 民政 (5) 30 | /// 31 | Civil = 53, 32 | /// 33 | /// 司法 (6) 34 | /// 35 | Justice = 54, 36 | /// 37 | /// 交通运输 (7) 38 | /// 39 | Transportation = 55, 40 | /// 41 | /// 文化 (8) 42 | /// 43 | Culture = 56, 44 | /// 45 | /// 工商 (9) 46 | /// 47 | Business = 57, 48 | /// 49 | /// 旅游局 (A) 50 | /// 51 | Tourism = 65, 52 | /// 53 | /// 宗教事务管理 (B) 54 | /// 55 | Religion = 66, 56 | /// 57 | /// 全国总工会 (C) 58 | /// 59 | ACFTU = 67, 60 | /// 61 | /// 人民解放军总后勤部 (D) 62 | /// 63 | ArmyLogisticsDepartment = 68, 64 | /// 65 | /// 省级人民政府 (E) 66 | /// 67 | ProvincialGovernment = 69, 68 | /// 69 | /// 地、市(设区)级人民政府 (F) 70 | /// 71 | MunicipalGovernment = 70, 72 | /// 73 | /// 区、县级人民政府 (G) 74 | /// 75 | CountyGovernment = 71, 76 | /// 77 | /// 其它 (Y) 78 | /// 79 | Other = 89, 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/ManagementKindCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos 6 | { 7 | /// 8 | /// 登记管理部门下机构类别代码标志,前两位对应ManagementCode,后两位为机构类别ASCII代码,未列举的登记管理部门则其机构类别标志统一使用NonSpecific 9 | /// 10 | public enum ManagementKindCode 11 | { 12 | /// 13 | /// 未指定类别 (1) 14 | /// 15 | NonSpecific = 49, 16 | /// 17 | /// 机构编制 -- 机关 (1) 18 | /// 19 | Office = 4949, 20 | /// 21 | /// 机构编制 -- 事业单位 (2) 22 | /// 23 | Institution = 4950, 24 | /// 25 | /// 机构编制 -- 中央编办直接管理机构编制的群众团体 (3) 26 | /// 27 | MassOrganizations = 4951, 28 | /// 29 | /// 机构编制 -- 其它 (9) 30 | /// 31 | InstitutionOther = 4957, 32 | /// 33 | /// 民政 -- 社会团体 (1) 34 | /// 35 | SocialGroups = 5349, 36 | /// 37 | /// 民政 -- 民办非企业单位 (2) 38 | /// 39 | PeopleRunNonEnterpriseUnits = 5350, 40 | /// 41 | /// 民政 -- 基金会 (3) 42 | /// 43 | Foundation = 5351, 44 | /// 45 | /// 民政 -- 其它 (9) 46 | /// 47 | CivilOther = 5357, 48 | /// 49 | /// 工商 -- 企业 (1) 50 | /// 51 | Enterprise = 5749, 52 | /// 53 | /// 工商 -- 个体工商户 (2) 54 | /// 55 | IndividualBusinesses = 5750, 56 | /// 57 | /// 工商 -- 农民专业合作社 (3) 58 | /// 59 | FarmerCooperatives = 5751, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/RegistrationNoLength.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos 6 | { 7 | /// 8 | /// 工商注册号长度 9 | /// 10 | public enum RegistrationNoLength 11 | { 12 | /// 13 | /// 15位,工商注册码 14 | /// 15 | Fifteen = 15, 16 | /// 17 | /// 18位,统一社会信用代码 18 | /// 19 | Eighteen = 18 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/RegistrationNoValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos 6 | { 7 | /// 8 | /// 注册码通用验证结果类 9 | /// 10 | public class RegistrationNoValidationResult : ValidationResult 11 | { 12 | /// 13 | /// 行政区划或工商行政管理机关编码 14 | /// 15 | public int AreaNumber { get; internal set; } 16 | /// 17 | /// 身份证颁发行政区域或工商行政管理机关(识别出Depth最深的区域),可通过FullName来获取完整的名称 18 | /// 注意此处有可能为null 19 | /// 20 | public Area RecognizableArea { get; internal set; } 21 | /// 22 | /// 号码长度 23 | /// 24 | public RegistrationNoLength RegistrationNoLength { get; internal set; } 25 | /// 26 | /// 校验码 27 | /// 28 | public char CheckBit { get; internal set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/ErrorMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos.Validators 6 | { 7 | /// 8 | /// 错误提示信息类 9 | /// 10 | internal static class ErrorMessage 11 | { 12 | /// 13 | /// 字符串为空 14 | /// 15 | public const string Empty = "工商注册码/统一社会信用代码为空"; 16 | /// 17 | /// 号码错误 18 | /// 19 | public const string Error = "错误的工商注册码/统一社会信用代码"; 20 | /// 21 | /// 无效的登记管理部门代码 22 | /// 23 | public const string InvalidManagement = "无效的登记管理部门代码"; 24 | /// 25 | /// 无效的登记管理部门机构类别代码 26 | /// 27 | public const string InvalidManagementKind = "无效的登记管理部门机构类别代码"; 28 | /// 29 | /// 无效的组织机构代码 30 | /// 31 | public const string InvalidOrganizationCode = "无效的组织机构代码"; 32 | /// 33 | /// 行政区划识别失败 34 | /// 35 | public const string InvalidArea = "工商管理机关或行政区划识别失败"; 36 | /// 37 | /// 错误的校验码 38 | /// 39 | public const string InvalidCheckBit = "错误的校验码"; 40 | /// 41 | /// 无效实现 42 | /// 43 | public const string InvalidImplement = "未能找到或无效的 {0} 位工商注册码/统一社会信用代码实现"; 44 | /// 45 | /// 长度错误 46 | /// 47 | public const string LengthOutOfRange = "工商注册码/统一社会信用代码非 {0} 位"; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/IRegistrationNoValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos.Validators 6 | { 7 | /// 8 | /// 工商注册码/统一社会信用代码验证接口 9 | /// 10 | public interface IRegistrationNoValidator : IValidator 11 | where TResult : RegistrationNoValidationResult, new() 12 | { 13 | /// 14 | /// 用于验证的行政区划字典数据 15 | /// 16 | IValidationDictionary Dictionary { get; set; } 17 | /// 18 | /// 号码长度 19 | /// 20 | RegistrationNoLength RegistrationNoLength { get; } 21 | /// 22 | /// 验证号码是否正确 23 | /// 24 | /// 待验证的工商注册码/统一社会信用代码 25 | /// 行政区划验证限制,因为存在工商管理机构代码,所以默认为null 26 | /// 27 | TResult Validate(string code, AreaValidLimit? validLimit = null); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNo15ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos.Validators 6 | { 7 | /// 8 | /// 工商行政管理市场主体注册号 专用验证结果类 9 | /// 10 | public class RegistrationNo15ValidationResult : RegistrationNoValidationResult 11 | { 12 | /// 13 | /// 顺序码 14 | /// 15 | public int SequenceNumber { get; internal set; } 16 | /// 17 | /// 企业类型 18 | /// 19 | public EnterpriseType EnterpriseType 20 | { 21 | get 22 | { 23 | var comp = this.SequenceNumber / 10000000; 24 | if (comp <= (int)EnterpriseType.Domestic) 25 | { 26 | return EnterpriseType.Domestic; 27 | } 28 | else if (comp <= (int)EnterpriseType.Foreign) 29 | { 30 | return EnterpriseType.Foreign; 31 | } 32 | else { return EnterpriseType.Individual; } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNo15Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace NumberValidators.BusinessRegistrationNos.Validators 9 | { 10 | /// 11 | /// GS15-2006 工商行政管理市场主体注册号编制规则 12 | /// 13 | public class RegistrationNo15Validator : RegistrationNoValidator 14 | { 15 | private IValidationDictionary _administrationDictionary; 16 | /// 17 | /// 默认的工商行政管理机关代码字典类 18 | /// 19 | protected IValidationDictionary DefaultAdministrationDictionary { get; } = AdministrationValidationDictionary.Singleton; 20 | /// 21 | /// 工商行政管理机关代码字典类 22 | /// 23 | public IValidationDictionary AdministrationDictionary 24 | { 25 | get 26 | { 27 | return this._administrationDictionary ?? DefaultAdministrationDictionary; 28 | } 29 | set 30 | { 31 | this._administrationDictionary = value; 32 | } 33 | } 34 | /// 35 | /// 号码长度 36 | /// 37 | public override RegistrationNoLength RegistrationNoLength => RegistrationNoLength.Fifteen; 38 | /// 39 | /// 验证用正则 40 | /// 41 | protected override string RegexPattern => RegexPatterns.BusinessRegistrationNo; 42 | /// 43 | /// 工商行政管理机关代码 44 | /// 45 | private sealed class AdministrationValidationDictionary : IValidationDictionary 46 | { 47 | private AdministrationValidationDictionary() { } 48 | /// 49 | /// 单例 50 | /// 51 | public static readonly AdministrationValidationDictionary Singleton = new AdministrationValidationDictionary(); 52 | private static readonly Dictionary Dictionary = new Dictionary 53 | { 54 | { 100000,"国家工商行政管理总局"}, 55 | }; 56 | public IDictionary GetDictionary() 57 | { 58 | return Dictionary; 59 | } 60 | } 61 | /// 62 | /// 生成工商注册号 63 | /// 64 | /// 65 | /// 66 | protected override string GenerateRegistrationNo(string areaNumber) 67 | { 68 | return this.GenerateRegistrationNo(areaNumber, RandomHelper.GetRandomNumber(10)); 69 | } 70 | /// 71 | /// 生成工商注册码 72 | /// 73 | /// 行政区划 74 | /// 企业类型 75 | /// 76 | public string GenerateRegistrationNo(int areaNumber, EnterpriseType enterpriseType) 77 | { 78 | var typeSeed = 4; 79 | if (enterpriseType == EnterpriseType.Foreign) 80 | { 81 | typeSeed = 2; 82 | } 83 | var rdType = (int)enterpriseType - RandomHelper.GetRandomNumber(typeSeed); 84 | return this.GenerateRegistrationNo(areaNumber.ToString().PadRight(6, '0').Substring(0, 6), rdType); 85 | } 86 | private string GenerateRegistrationNo(string areaNumber, int rdType) 87 | { 88 | var seqNumber = RandomHelper.GetRandomNumber(10000000).ToString().PadLeft(7, '0'); 89 | var tmp = string.Format("{0}{1}{2}", areaNumber, rdType, seqNumber); 90 | return string.Format("{0}{1}", tmp, this.GetCheckBit(tmp)); 91 | } 92 | /// 93 | /// 验证行政区划 94 | /// 95 | /// 96 | /// 97 | /// 98 | /// 99 | protected override bool ValidArea(string code, AreaValidLimit? validLimit, RegistrationNo15ValidationResult result) 100 | { 101 | var areaNumber = this.GetAreaNumber(code); 102 | var area = AreaHelper.GetDeepestArea(result.AreaNumber, this.AdministrationDictionary); 103 | result.AreaNumber = areaNumber; 104 | var valid = true; 105 | if (area != null) 106 | { 107 | result.RecognizableArea = area; 108 | } 109 | else 110 | { 111 | valid = base.ValidArea(code, validLimit, result); 112 | } 113 | return valid; 114 | } 115 | /// 116 | /// 获取行政区划代码 117 | /// 118 | /// 119 | /// 120 | protected override int GetAreaNumber(string code) 121 | { 122 | return int.Parse(code.Substring(0, 6)); 123 | } 124 | /// 125 | /// 验证校验位 126 | /// 127 | /// 128 | /// 129 | /// 130 | protected override bool IsCheckBitRight(string code, out char rightBit) 131 | { 132 | rightBit = this.GetCheckBit(code); 133 | return code[code.Length - 1] == rightBit; 134 | } 135 | private char GetCheckBit(string code) 136 | { 137 | var mod = GBT17710_1999.MOD_11_10(code.Select(c => (int)c - 48).Take(14).ToArray()); 138 | return (char)(mod + 48); 139 | } 140 | /// 141 | /// 验证其它信息 142 | /// 143 | /// 144 | /// 145 | /// 146 | protected override bool ValidOtherInfo(string code, RegistrationNo15ValidationResult result) 147 | { 148 | result.SequenceNumber = int.Parse(code.Substring(6, 8)); 149 | return base.ValidOtherInfo(code, result); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNo18ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.BusinessRegistrationNos.Validators 6 | { 7 | /// 8 | /// 法人和其他组织统一社会信用代码 专用验证结果类 9 | /// 10 | public class RegistrationNo18ValidationResult : RegistrationNoValidationResult 11 | { 12 | /// 13 | /// 登记管理部门代码标志 14 | /// 15 | public ManagementCode ManagementCode { get; internal set; } 16 | /// 17 | /// 登记管理部门下机构类别代码标志 18 | /// 19 | public ManagementKindCode ManagementKindCode { get; internal set; } = ManagementKindCode.NonSpecific; 20 | /// 21 | /// 组织机构代码,遵循GB/T 11714-1997 22 | /// 23 | public string OrganizationCode { get; internal set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNo18Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using NumberValidators.Utils.ISO; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace NumberValidators.BusinessRegistrationNos.Validators 10 | { 11 | /// 12 | /// GB 32100-2015 法人和其他组织统一社会信用代码编码规则 13 | /// 14 | public class RegistrationNo18Validator : RegistrationNoValidator 15 | { 16 | #region fields 17 | /// 18 | /// 本体代码及其对应的代码字符数值,不使用字母IOZSV 19 | /// 20 | internal static readonly Dictionary CodeDictionary = new Dictionary(); 21 | /// 22 | /// 加权因子 23 | /// 24 | internal static readonly int[] WeightingFactors = { 1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28 }; 25 | private static readonly HashSet ManagementCodes = new HashSet(Enum.GetValues(typeof(ManagementCode)).Cast()); 26 | private static readonly HashSet ManagementKindCodes = new HashSet(Enum.GetValues(typeof(ManagementKindCode)).Cast().Select(c => (int)c)); 27 | #endregion 28 | 29 | #region props 30 | /// 31 | /// 号码长度 32 | /// 33 | public override RegistrationNoLength RegistrationNoLength => RegistrationNoLength.Eighteen; 34 | /// 35 | /// 验证用的正则 36 | /// 37 | protected override string RegexPattern => RegexPatterns.UnifiedSocialCreditCode; 38 | #endregion 39 | 40 | #region oct 41 | static RegistrationNo18Validator() 42 | { 43 | for (var i = 0; i <= 30; i++) 44 | { 45 | int num; 46 | if (i > 27) { num = 59; } 47 | else if (i > 25) { num = 58; } 48 | else if (i > 22) { num = 57; } 49 | else if (i > 17) { num = 56; } 50 | else if (i > 9) { num = 55; } 51 | else { num = 48; } 52 | var c = (char)(num + i); 53 | CodeDictionary.Add(c, i); 54 | } 55 | } 56 | #endregion 57 | /// 58 | /// 生成随机的统一社会信用代码 59 | /// 60 | /// 61 | /// 62 | protected override string GenerateRegistrationNo(string areaNumber) 63 | { 64 | ManagementCode code = ManagementCodes.OrderBy(g => Guid.NewGuid()).First(); 65 | return this.GenerateRegistrationNo(Convert.ToInt32(areaNumber), code); 66 | } 67 | /// 68 | /// 生成统一社会信用代码 69 | /// 70 | /// 71 | /// 72 | /// 73 | public string GenerateRegistrationNo(int areaNumber, ManagementCode code) 74 | { 75 | ManagementKindCode kind = ManagementKindCode.NonSpecific; 76 | var query = ManagementKindCodes.Where(c => c / 100 == (int)code); 77 | if (query.Any()) 78 | { 79 | kind = (ManagementKindCode)query.OrderBy(g => Guid.NewGuid()).First(); 80 | } 81 | return this.GenerateRegistrationNo(areaNumber.ToString().PadRight(6, '0').Substring(0, 6), code, kind); 82 | } 83 | /// 84 | /// 生成统一社会信用代码 85 | /// 86 | /// 87 | /// 88 | /// 89 | /// 90 | public string GenerateRegistrationNo(int areaNumber, ManagementCode code, ManagementKindCode kind) 91 | { 92 | return this.GenerateRegistrationNo(areaNumber.ToString().PadRight(6, '0').Substring(0, 6), code, kind); 93 | } 94 | private string GenerateRegistrationNo(string areaNumber, ManagementCode code, ManagementKindCode kind) 95 | { 96 | var tmp = string.Format("{0}{1}{2}{3}", (char)((int)code), (char)((int)kind % 100), areaNumber, this.GenerateOrganizationCode()); 97 | return string.Format("{0}{1}", tmp, this.GetCheckBit(tmp)); 98 | } 99 | private string GenerateOrganizationCode() 100 | { 101 | var tmp = new string(Enumerable.Repeat(1, 4).SelectMany(i => 102 | { 103 | var rd = RandomHelper.GetRandomNumber(961); 104 | return new int[] { rd / 31, rd % 31 }; 105 | }).Select(k => CodeDictionary.First(kv => kv.Value == k).Key).ToArray()); 106 | return string.Format("{0}{1}", tmp, this.GetOrganizationCodeCheckBit(tmp)); 107 | } 108 | /// 109 | /// 获取行政区划编码 110 | /// 111 | /// 112 | /// 113 | protected override int GetAreaNumber(string code) 114 | { 115 | return int.Parse(code.Substring(2, 6)); 116 | } 117 | /// 118 | /// 验证校验位 119 | /// 120 | /// 121 | /// 122 | /// 123 | protected override bool IsCheckBitRight(string code, out char rightBit) 124 | { 125 | rightBit = this.GetCheckBit(code); 126 | return rightBit == code[17]; 127 | } 128 | private char GetCheckBit(string code) 129 | { 130 | var mod = (31 - ISO7064_1983.MOD_11_2(code.Select(c => CodeDictionary[c]).Take(17).ToArray(), WeightingFactors, 31)) % 31; 131 | return CodeDictionary.First(kv => kv.Value == mod).Key; 132 | } 133 | /// 134 | /// 验证其它信息 135 | /// 136 | /// 137 | /// 138 | /// 139 | protected override bool ValidOtherInfo(string code, RegistrationNo18ValidationResult result) 140 | { 141 | return base.ValidOtherInfo(code, result) 142 | && this.ValidManagementCode(code, result) 143 | && this.ValidManagementKindCode(code, result) 144 | && this.ValidOrganizationCode(code, result); 145 | } 146 | private bool ValidManagementCode(string code, RegistrationNo18ValidationResult result) 147 | { 148 | var valid = Enum.TryParse(((int)code[0]).ToString(), out ManagementCode mc) && ManagementCodes.Contains(mc); 149 | if (!valid) 150 | { 151 | result.AddErrorMessage(ErrorMessage.InvalidManagement); 152 | } 153 | else 154 | { 155 | result.ManagementCode = mc; 156 | } 157 | return valid; 158 | } 159 | private bool ValidManagementKindCode(string code, RegistrationNo18ValidationResult result) 160 | { 161 | var valid = Enum.TryParse(((int)result.ManagementCode * 100 + (int)code[1]).ToString(), out ManagementKindCode mkc) 162 | && ManagementKindCodes.Contains((int)mkc); 163 | if (!valid && (int)code[1] == (int)ManagementKindCode.NonSpecific) 164 | { 165 | valid = true; 166 | mkc = ManagementKindCode.NonSpecific; 167 | } 168 | if (!valid) 169 | { 170 | result.AddErrorMessage(ErrorMessage.InvalidManagementKind); 171 | } 172 | else 173 | { 174 | result.ManagementKindCode = mkc; 175 | } 176 | return valid; 177 | } 178 | private bool ValidOrganizationCode(string code, RegistrationNo18ValidationResult result) 179 | { 180 | var orgCode = code.Substring(8, 9); 181 | result.OrganizationCode = orgCode; 182 | var valid = orgCode[8] == this.GetOrganizationCodeCheckBit(orgCode); 183 | if (!valid) 184 | { 185 | result.AddErrorMessage(ErrorMessage.InvalidOrganizationCode); 186 | } 187 | return valid; 188 | } 189 | private char GetOrganizationCodeCheckBit(string orgCode) 190 | { 191 | return GBT11714_1997.GetCheckBit(orgCode); 192 | } 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNoValidator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace NumberValidators.BusinessRegistrationNos.Validators 9 | { 10 | /// 11 | /// 工商注册号/统一社会信用代码模板基类 12 | /// 13 | public abstract class RegistrationNoValidator : BaseValidatorWithDictionary, IRegistrationNoValidator 14 | where TResult : RegistrationNoValidationResult, new() 15 | { 16 | #region props 17 | /// 18 | /// 号码长度 19 | /// 20 | public abstract RegistrationNoLength RegistrationNoLength { get; } 21 | /// 22 | /// 默认的行政区划字典 23 | /// 24 | protected override IValidationDictionary DefaultDictionary => GBT2260_2013.Singleton; 25 | /// 26 | /// 空提示 27 | /// 28 | protected override string EmptyErrorMessage => ErrorMessage.Empty; 29 | /// 30 | /// 正则验证失败提示 31 | /// 32 | protected override string RegexMatchFailMessage => ErrorMessage.Error; 33 | #endregion 34 | 35 | #region interfaces 36 | /// 37 | /// 生成随机的号码 38 | /// 39 | /// 40 | public override string GenerateRandomNumber() 41 | { 42 | var areaNumber = this.Dictionary.GetDictionary().Keys.OrderBy(g => Guid.NewGuid()).FirstOrDefault(i => i > 10000 && i < 1000000); 43 | if (areaNumber == 0) 44 | { 45 | throw new ArgumentException("GB2312 dictionary is not correct."); 46 | } 47 | return this.GenerateRegistrationNo(areaNumber.ToString().PadRight(6, '0')); 48 | } 49 | /// 50 | /// 生成工商注册号/统一社会信用代码 51 | /// 52 | /// 53 | /// 54 | protected abstract string GenerateRegistrationNo(string areaNumber); 55 | /// 56 | /// 验证号码是否正确 57 | /// 58 | /// 59 | /// 60 | public override TResult Validate(string number) 61 | { 62 | return this.Validate(number, null); 63 | } 64 | /// 65 | /// 验证号码是否正确 66 | /// 67 | /// 待验证的工商注册码/统一社会信用代码 68 | /// 行政区划验证限制,因为存在工商管理机构代码,所以默认为null 69 | public TResult Validate(string code, AreaValidLimit? validLimit = null) 70 | { 71 | var result = base.Validate(code); 72 | _ = result.IsValid 73 | && this.ValidArea(code, validLimit, result) 74 | && this.ValidCheckBit(code, result) 75 | && this.ValidOtherInfo(code, result); 76 | return result; 77 | } 78 | #endregion 79 | 80 | #region methods 81 | /// 82 | /// 验证行政区划 83 | /// 84 | /// 85 | /// 86 | /// 87 | /// 88 | protected virtual bool ValidArea(string code, AreaValidLimit? validLimit, TResult result) 89 | { 90 | var areaNumber = this.GetAreaNumber(code); 91 | var area = AreaHelper.GetDeepestArea(areaNumber, this.Dictionary); 92 | bool valid = !validLimit.HasValue || (area != null && area.GetDepth() >= (int)validLimit); 93 | result.RecognizableArea = area; 94 | result.AreaNumber = areaNumber; 95 | if (!valid) 96 | { 97 | result.AddErrorMessage(ErrorMessage.InvalidArea); 98 | } 99 | return valid; 100 | } 101 | /// 102 | /// 获取行政区划代码 103 | /// 104 | /// 105 | /// 106 | protected abstract int GetAreaNumber(string code); 107 | private bool ValidCheckBit(string code, TResult result) 108 | { 109 | bool valid = this.IsCheckBitRight(code, out char rightBit); 110 | result.CheckBit = rightBit; 111 | if (!valid) 112 | { 113 | result.AddErrorMessage(ErrorMessage.InvalidCheckBit); 114 | } 115 | return valid; 116 | } 117 | /// 118 | /// 判断校验位是否正确 119 | /// 120 | /// 待校验的号码 121 | /// 正确的校验位 122 | /// 123 | protected abstract bool IsCheckBitRight(string code, out char rightBit); 124 | /// 125 | /// 验证其它信息 126 | /// 127 | /// 128 | /// 129 | /// 130 | protected virtual bool ValidOtherInfo(string code, TResult result) 131 | { 132 | result.RegistrationNoLength = this.RegistrationNoLength; 133 | return true; 134 | } 135 | #endregion 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/NumberValidators/BusinessRegistrationNos/Validators/RegistrationNoValidatorHelper.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace NumberValidators.BusinessRegistrationNos.Validators 8 | { 9 | /// 10 | /// 工商注册号、统一社会信用代码验证帮助类 11 | /// 12 | public static class RegistrationNoValidatorHelper 13 | { 14 | private static readonly ConcurrentDictionary> concurrentDictionary 15 | = new ConcurrentDictionary>(); 16 | static RegistrationNoValidatorHelper() 17 | { 18 | ResetDefaultValidator(); 19 | } 20 | /// 21 | /// 验证工商注册号、统一社会信用代码是否正确 22 | /// 23 | /// 工商注册号、统一社会信用代码 24 | /// 要验证的证件长度,默认不指定null 25 | /// 验证区域级别,默认不指定null 26 | /// 验证结果 27 | public static RegistrationNoValidationResult Validate(this string code, int? validLength = null, AreaValidLimit? validLimit = null) 28 | { 29 | IRegistrationNoValidator validator = null; 30 | _ = ValidatorHelper.ValidEmpty(code, out RegistrationNoValidationResult result, ErrorMessage.Empty) 31 | && ValidatorHelper.ValidLength(code, validLength, ErrorMessage.LengthOutOfRange, result) 32 | && ValidImplement(code, result, out validator); 33 | return validator == null ? result : validator.Validate(code, validLimit); 34 | } 35 | 36 | private static bool ValidImplement(string code, RegistrationNoValidationResult result, out IRegistrationNoValidator validator) 37 | { 38 | _ = concurrentDictionary.TryGetValue(code.Length, out validator) 39 | || ValidatorHelper.ValidImplement(code, result, "RegistrationNo{0}Validator", ErrorMessage.InvalidImplement, out validator, typeof(IRegistrationNoValidator<>)); 40 | return validator != null; 41 | } 42 | 43 | /// 44 | /// 设置证件号长度对应的校验规则 45 | /// 46 | /// 校验实现对应的编号长度 47 | /// 默认实现 48 | public static void SetValidator(int noLength, IRegistrationNoValidator validator) 49 | { 50 | if (validator == null) 51 | { 52 | throw new ArgumentNullException(nameof(validator)); 53 | } 54 | concurrentDictionary.AddOrUpdate(noLength, k => validator, (k, a) => validator); 55 | } 56 | /// 57 | /// 添加或重置默认已提供的对应实现,用于临时解决core下可能会出现的反射错误 58 | /// 59 | public static void ResetDefaultValidator() 60 | { 61 | concurrentDictionary.AddOrUpdate((int)RegistrationNoLength.Fifteen, k => new RegistrationNo15Validator(), (k, a) => new RegistrationNo15Validator()); 62 | concurrentDictionary.AddOrUpdate((int)RegistrationNoLength.Eighteen, k => new RegistrationNo18Validator(), (k, a) => new RegistrationNo18Validator()); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/NumberValidators/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | // This file is used by Code Analysis to maintain SuppressMessage 2 | // attributes that are applied to this project. 3 | // Project-level suppressions either have no target or are given 4 | // a specific target and scoped to a namespace, type, member, etc. 5 | 6 | using System.Diagnostics.CodeAnalysis; 7 | 8 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.IVATCodeValidator`1")] 9 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCode10ValidationResult")] 10 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCode10Validator")] 11 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCode12ValidationResult")] 12 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCode12Validator")] 13 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCodeValidator`1")] 14 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.Validators.VATCodeValidatorHelper")] 15 | 16 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.GBT2260OnlyProvince")] 17 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Invoices.VATCodeValidationResult")] 18 | 19 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.GBT.GBT11714_1997")] 20 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.GBT.GBT17710_1999")] 21 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.GBT.GBT2260")] 22 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.GBT.GBT2260_2013")] 23 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.GBT.GBT2659_2000OfDigitalCode")] 24 | [assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "<挂起>", Scope = "type", Target = "~T:NumberValidators.Utils.ISO.ISO7064_1983")] -------------------------------------------------------------------------------- /src/NumberValidators/IValidationDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators 7 | { 8 | /// 9 | /// 验证用的基础数据字典接口 10 | /// 11 | /// 12 | /// 13 | public interface IValidationDictionary 14 | { 15 | /// 16 | /// 获取验证所需的字典 17 | /// 18 | /// 19 | IDictionary GetDictionary(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/NumberValidators/IValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators 7 | { 8 | /// 9 | /// 所有号码验证类均需实现的基础接口定义 10 | /// 11 | /// 12 | public interface IValidator 13 | where T : ValidationResult, new() 14 | { 15 | /// 16 | /// 随机生成一个符合规则的号码 17 | /// 18 | /// 19 | string GenerateRandomNumber(); 20 | /// 21 | /// 验证号码是否正确 22 | /// 23 | /// 24 | /// 25 | T Validate(string number); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Gender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.IdentityCards 7 | { 8 | /// 9 | /// 性别 10 | /// 11 | public enum Gender 12 | { 13 | /// 14 | /// 女性 15 | /// 16 | Female = 0, 17 | /// 18 | /// 男性 19 | /// 20 | Male = 1, 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/IDLength.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.IdentityCards 7 | { 8 | /// 9 | /// 身份证号码长度 10 | /// 11 | public enum IDLength 12 | { 13 | /// 14 | /// 15位长度身份证 15 | /// 16 | Fifteen = 15, 17 | /// 18 | /// 18位长度身份证 19 | /// 20 | Eighteen = 18 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/IDValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.IdentityCards 7 | { 8 | /// 9 | /// 身份证验证结果类 10 | /// 11 | public class IDValidationResult : ValidationResult 12 | { 13 | /// 14 | /// 身份证号码长度 15 | /// 16 | public IDLength IDLength { get; internal set; } 17 | /// 18 | /// 身份证上的出生日期 19 | /// 20 | public DateTime Birthday { get; internal set; } 21 | /// 22 | /// 性别 23 | /// 24 | public Gender Gender { get; internal set; } 25 | /// 26 | /// 行政区划编码 27 | /// 28 | public int AreaNumber { get; internal set; } 29 | /// 30 | /// 身份证颁发行政区域(识别出Depth最深的区域),可通过FullName来获取完整的区域名 31 | /// 32 | public Area RecognizableArea { get; internal set; } 33 | /// 34 | /// 出生登记顺序号 35 | /// 36 | public int Sequence { get; internal set; } 37 | /// 38 | /// 身份证校验码 39 | /// 40 | public char CheckBit { get; internal set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/ErrorMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.IdentityCards.Validators 7 | { 8 | /// 9 | /// 错误提示信息类 10 | /// 11 | internal static class ErrorMessage 12 | { 13 | /// 14 | /// 身份证号码为空 15 | /// 16 | public const string Empty = "身份证号码为空"; 17 | /// 18 | /// 错误的身份证号码 19 | /// 20 | public const string Error = "错误的身份证号码"; 21 | /// 22 | /// 无效的出生日期 23 | /// 24 | public const string InvalidBirthday = "无效的出生日期"; 25 | /// 26 | /// 出生日期超出允许的年份范围 27 | /// 28 | public const string BirthdayYearOutOfRange = "出生日期超出允许的年份范围{0} ~ {1}"; 29 | /// 30 | /// 行政区划识别失败 31 | /// 32 | public const string InvalidArea = "行政区划识别失败"; 33 | /// 34 | /// 行政区划识别度不足 35 | /// 36 | public const string AreaLimitOutOfRange = "行政区划识别度低于识别级别 {0}"; 37 | /// 38 | /// 错误的校验码 39 | /// 40 | public const string InvalidCheckBit = "错误的校验码"; 41 | /// 42 | /// 无效实现 43 | /// 44 | public const string InvalidImplement = "未能找到或无效的 {0} 位身份证实现"; 45 | /// 46 | /// 长度错误 47 | /// 48 | public const string LengthOutOfRange = "身份证号码非 {0} 位"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/ID15Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Globalization; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace NumberValidators.IdentityCards.Validators 9 | { 10 | /// 11 | /// 15位旧身份证校验规则 12 | /// 13 | public class ID15Validator : IDValidator 14 | { 15 | /* 16 | 15位身份证号码各位的含义: 17 | 1-2位省、自治区、直辖市代码; 18 | 3-4位地级市、盟、自治州代码; 19 | 5-6位县、县级市、区代码; 20 | 7-12位出生年月日,比如670401代表1967年4月1日,这是和18位号码的第一个区别; 21 | 13-15位为顺序号,其中15位男为单数,女为双数; 22 | 与18位身份证号的第二个区别:没有最后一位的验证码。 23 | 24 | 15位身份证号码升级成18位身份证号码时,并不会修正GB/T 2260发生变化导致的区域编号变更,所以如果按最新的GBT2260标准进行身份证校验,会导致有些正确的身份证校验失败 25 | */ 26 | /// 27 | /// 证件长度 28 | /// 29 | public override IDLength IDLength => IDLength.Fifteen; 30 | /// 31 | /// 验证用的正则表达式 32 | /// 33 | protected override string RegexPattern => RegexPatterns.FirstIdentityCard; 34 | /// 35 | /// 生成身份证 36 | /// 37 | /// 38 | /// 39 | /// 40 | /// 41 | protected override string GenerateID(string areaNumber, DateTime birthDay, string sequenceNumber) 42 | { 43 | return string.Format("{0}{1:yyMMdd}{2}", areaNumber, birthDay, sequenceNumber); 44 | } 45 | /// 46 | /// 获取出生日期 47 | /// 48 | /// 49 | /// 50 | protected override DateTime GetBirthday(string idNumber) 51 | { 52 | DateTime.TryParseExact("19" + idNumber.Substring(6, 6), "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date); 53 | return date; 54 | } 55 | /// 56 | /// 获取登记序列号 57 | /// 58 | /// 59 | /// 60 | protected override string GetSequenceNumber(string idNumber) 61 | { 62 | return idNumber.Substring(12, 3); 63 | } 64 | /// 65 | /// 校验位是否正确 66 | /// 67 | /// 68 | /// 69 | /// 70 | protected override bool IsCheckBitRight(string idNumber, out char rightBit) 71 | { 72 | rightBit = char.MinValue; 73 | return true; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/ID18Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.ISO; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Globalization; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace NumberValidators.IdentityCards.Validators 10 | { 11 | /// 12 | /// 18位(新)身份证校验规则 13 | /// 14 | public class ID18Validator : IDValidator 15 | { 16 | /* 17 | 18位身份证号码各位数字的含义: 18 | 1-2位省、自治区、直辖市代码; 19 | 3-4位地级市、盟、自治州代码; 20 | 5-6位县、县级市、区代码; 21 | 7-14位出生年月日,比如19670401代表1967年4月1日,遵循GB/T 7408-1994标准; 22 | 15-17位为顺序号,其中17位男为单数,女为双数; 23 | 18位为校验码,0-9和X,由公式随机产生。 举例: 130503196704010012这个身份证号的含义:13为河北,05为邢台,03为桥西区,出生日期为1967年4月1日,顺序号为001,2为验证码。 24 | */ 25 | /// 26 | /// 证件长度 27 | /// 28 | public override IDLength IDLength => IDLength.Eighteen; 29 | /// 30 | /// 验证用的正则表达式 31 | /// 32 | protected override string RegexPattern => RegexPatterns.SecondIdentityCard; 33 | /// 34 | /// 生成身份证 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// 40 | protected override string GenerateID(string areaNumber, DateTime birthDay, string sequenceNumber) 41 | { 42 | var tmp = string.Format("{0}{1:yyyyMMdd}{2}", areaNumber, birthDay, sequenceNumber); 43 | var checkBit = this.GetCheckBit(tmp); 44 | return string.Format("{0}{1}", tmp, checkBit); 45 | } 46 | /// 47 | /// 获取出生日期 48 | /// 49 | /// 50 | /// 51 | protected override DateTime GetBirthday(string idNumber) 52 | { 53 | DateTime.TryParseExact(idNumber.Substring(6, 8), "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime date); 54 | return date; 55 | } 56 | /// 57 | /// 获取登记序列号 58 | /// 59 | /// 60 | /// 61 | protected override string GetSequenceNumber(string idNumber) 62 | { 63 | return idNumber.Substring(14, 3); 64 | } 65 | /// 66 | /// 校验码加权因子 67 | /// 68 | private static readonly int[] WeightingFactors = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 }; 69 | /// 70 | /// 按照ISO7064:1983.MOD取模结果对应的校验码(对应数组索引) 71 | /// 72 | private static readonly char[] CheckBits = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' }; 73 | /// 74 | /// 校验位是否正确 75 | /// 76 | /// 77 | /// 78 | /// 79 | protected override bool IsCheckBitRight(string idNumber, out char rightBit) 80 | { 81 | rightBit = GetCheckBit(idNumber); 82 | return rightBit == idNumber[17]; 83 | } 84 | private char GetCheckBit(string idNumber) 85 | { 86 | var mod = ISO7064_1983.MOD_11_2(idNumber.Select(c => (int)c - 48).Take(17).ToArray(), WeightingFactors, 11); 87 | return CheckBits[mod]; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/IDValidator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using NumberValidators.Utils.GBT; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace NumberValidators.IdentityCards.Validators 9 | { 10 | /// 11 | /// 身份证验证模板基类 12 | /// 13 | public abstract class IDValidator : BaseValidatorWithDictionary, IIDValidator 14 | { 15 | #region props 16 | /// 17 | /// 默认数据字典类 18 | /// 19 | protected override IValidationDictionary DefaultDictionary => GBT2260_2013.Singleton; 20 | /// 21 | /// 身份证长度 22 | /// 23 | public abstract IDLength IDLength { get; } 24 | /// 25 | /// 空提示 26 | /// 27 | protected override string EmptyErrorMessage => ErrorMessage.Empty; 28 | /// 29 | /// 正则验证失败提示 30 | /// 31 | protected override string RegexMatchFailMessage => ErrorMessage.Error; 32 | #endregion 33 | 34 | #region interface 35 | /// 36 | /// 生成随机的身份证号码 37 | /// 38 | /// 39 | public override string GenerateRandomNumber() 40 | { 41 | var areaNumber = this.Dictionary.GetDictionary().Keys.OrderBy(g => Guid.NewGuid()).FirstOrDefault(i => i > 10000 && i < 1000000); 42 | if (areaNumber == 0) 43 | { 44 | throw new ArgumentException("GB2312 dictionary is not correct."); 45 | } 46 | var dtNow = DateTime.Now.Date; 47 | var year = dtNow.Year - RandomHelper.GetRandomNumber(120); 48 | var month = RandomHelper.GetRandomNumber(dtNow.Year == year ? dtNow.Month : 12) + 1; 49 | var tmpDate = new DateTime(year, month, 1).AddMonths(1).AddDays(-1); 50 | var day = RandomHelper.GetRandomNumber((dtNow < tmpDate ? dtNow : tmpDate).Day) + 1; 51 | var sequenceNumber = RandomHelper.GetRandomNumber(1000); 52 | return this.GenerateID(areaNumber, new DateTime(year, month, day), sequenceNumber); 53 | } 54 | /// 55 | /// 生成身份证号码 56 | /// 57 | /// 58 | /// 59 | /// 60 | /// 61 | public virtual string GenerateID(int areaNumber, DateTime birthDay, int sequenceNumber) 62 | { 63 | if (areaNumber < 10 || areaNumber > 999999 || sequenceNumber < 0 || sequenceNumber > 999) 64 | { 65 | throw new ArgumentException("argument error"); 66 | } 67 | return this.GenerateID(areaNumber.ToString().PadRight(6, '0'), birthDay, sequenceNumber.ToString().PadLeft(3, '0')); 68 | } 69 | /// 70 | /// 生成身份证号码 71 | /// 72 | /// 73 | /// 74 | /// 75 | /// 76 | protected abstract string GenerateID(string areaNumber, DateTime birthDay, string sequenceNumber); 77 | /// 78 | /// 身份证验证 79 | /// 80 | /// 81 | /// 82 | public override IDValidationResult Validate(string number) 83 | { 84 | return this.Validate(number, ushort.MinValue); 85 | } 86 | /// 87 | /// 验证身份证是否正确 88 | /// 89 | /// 待验证的证件号码 90 | /// 允许最小年份,默认0 91 | /// 验证区域级别,默认AreaValidLimit.Province 92 | /// 是否忽略校验位验证,默认false 93 | /// 验证结果 94 | public IDValidationResult Validate(string idNumber, ushort minYear = 0, AreaValidLimit validLimit = AreaValidLimit.Province, bool ignoreCheckBit = false) 95 | { 96 | var result = base.Validate(idNumber); 97 | _ = result.IsValid 98 | && this.ValidBirthday(idNumber, minYear, result) 99 | && this.ValidArea(idNumber, validLimit, result) 100 | && this.ValidCheckBit(idNumber, ignoreCheckBit, result) 101 | && this.ValidOtherInfo(idNumber, result); 102 | return result; 103 | } 104 | #endregion 105 | 106 | #region methods 107 | private bool ValidBirthday(string idNumber, ushort minYear, IDValidationResult result) 108 | { 109 | var birthday = this.GetBirthday(idNumber); 110 | var dtNow = DateTime.Now.Date; 111 | bool valid = birthday > DateTime.MinValue && birthday.Year >= minYear && birthday <= dtNow; 112 | result.Birthday = birthday; 113 | if (!valid) 114 | { 115 | if (birthday == DateTime.MinValue || birthday > dtNow) 116 | { 117 | result.AddErrorMessage(ErrorMessage.InvalidBirthday); 118 | } 119 | else 120 | { 121 | result.AddErrorMessage(ErrorMessage.BirthdayYearOutOfRange, minYear, dtNow.Year); 122 | } 123 | } 124 | return valid; 125 | } 126 | /// 127 | /// 根据证件号获取出生日期,如果获取失败则返回DateTime.MinValue 128 | /// 129 | /// 130 | /// 131 | protected abstract DateTime GetBirthday(string idNumber); 132 | /// 133 | /// 验证行政区划 134 | /// 135 | /// 136 | /// 137 | /// 138 | /// 139 | protected virtual bool ValidArea(string idNumber, AreaValidLimit validLimit, IDValidationResult result) 140 | { 141 | int areaNumber = this.GetAreaNumber(idNumber); 142 | var area = AreaHelper.GetDeepestArea(areaNumber, this.Dictionary); 143 | bool valid = area != null && area.GetDepth() >= (int)validLimit; 144 | result.RecognizableArea = area; 145 | result.AreaNumber = areaNumber; 146 | if (!valid) 147 | { 148 | if (area == null) 149 | { 150 | result.AddErrorMessage(ErrorMessage.InvalidArea); 151 | } 152 | else 153 | { 154 | result.AddErrorMessage(ErrorMessage.AreaLimitOutOfRange, validLimit); 155 | } 156 | } 157 | return valid; 158 | } 159 | /// 160 | /// 获取行政区划编号 161 | /// 162 | /// 163 | /// 164 | protected virtual int GetAreaNumber(string idNumber) 165 | { 166 | return int.Parse(idNumber.Substring(0, 6)); 167 | } 168 | private bool ValidCheckBit(string idNumber, bool ignoreCheckBit, IDValidationResult result) 169 | { 170 | bool valid = this.IsCheckBitRight(idNumber, out char rightBit); 171 | result.CheckBit = rightBit; 172 | valid = valid || ignoreCheckBit; 173 | if (!valid) 174 | { 175 | result.AddErrorMessage(ErrorMessage.InvalidCheckBit); 176 | } 177 | return valid; 178 | } 179 | /// 180 | /// 判断校验位是否正确 181 | /// 182 | /// 183 | /// 184 | /// 185 | protected abstract bool IsCheckBitRight(string idNumber, out char rightBit); 186 | /// 187 | /// 验证并填充其它信息 188 | /// 189 | /// 190 | /// 191 | /// 192 | protected virtual bool ValidOtherInfo(string idNumber, IDValidationResult result) 193 | { 194 | int sequence = int.Parse(this.GetSequenceNumber(idNumber)); 195 | result.Gender = (Gender)(sequence % 2); 196 | result.Sequence = sequence; 197 | result.IDLength = (IDLength)idNumber.Length; 198 | return true; 199 | } 200 | /// 201 | /// 获取出生登记序列号 202 | /// 203 | /// 204 | protected abstract string GetSequenceNumber(string idNumber); 205 | 206 | #endregion 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/IDValidatorHelper.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace NumberValidators.IdentityCards.Validators 9 | { 10 | /// 11 | /// 身份证验证帮助类 12 | /// 13 | public static class IDValidatorHelper 14 | { 15 | private static readonly ConcurrentDictionary concurrentDictionary 16 | = new ConcurrentDictionary(); 17 | 18 | static IDValidatorHelper() 19 | { 20 | ResetDefaultValidator(); 21 | } 22 | 23 | /// 24 | /// 身份证升位,如果返回false表示升位失败,输入的旧身份证号码不正确 25 | /// 26 | /// 15位身份证号码 27 | /// 18位身份证号码 28 | /// 29 | public static bool TryPromotion(this string oldID, out string newID) 30 | { 31 | newID = null; 32 | var valid = new ID15Validator().Validate(oldID); 33 | if (valid.IsValid) 34 | { 35 | newID = new ID18Validator().GenerateID(valid.AreaNumber, valid.Birthday, valid.Sequence); 36 | } 37 | return valid.IsValid; 38 | } 39 | /// 40 | /// 验证身份证是否正确 41 | /// 42 | /// 待验证的证件号码 43 | /// 允许最小年份,默认0 44 | /// 要验证的证件长度,默认不指定null 45 | /// 验证区域级别,默认AreaValidLimit.Province 46 | /// 是否忽略校验位验证,默认false 47 | /// 验证结果 48 | public static IDValidationResult Validate(this string idNumber, ushort minYear = 0, int? validLength = null, AreaValidLimit validLimit = AreaValidLimit.Province, bool ignoreCheckBit = false) 49 | { 50 | IIDValidator validator = null; 51 | _ = ValidatorHelper.ValidEmpty(idNumber, out IDValidationResult result, ErrorMessage.Empty) 52 | && ValidatorHelper.ValidLength(idNumber, validLength, ErrorMessage.LengthOutOfRange, result) 53 | && ValidImplement(idNumber, result, out validator); 54 | return validator == null ? result : validator.Validate(idNumber, minYear, validLimit, ignoreCheckBit); 55 | } 56 | 57 | private static bool ValidImplement(string code, IDValidationResult result, out IIDValidator validator) 58 | { 59 | _ = concurrentDictionary.TryGetValue(code.Length, out validator) 60 | || ValidatorHelper.ValidImplement(code, result, "ID{0}Validator", ErrorMessage.InvalidImplement, out validator, typeof(IIDValidator)); 61 | return validator != null; 62 | } 63 | 64 | /// 65 | /// 设置证件号长度对应的校验规则 66 | /// 67 | /// 默认校验实现对应的编号长度 68 | /// 默认实现 69 | public static void SetValidator(int idLength, IIDValidator validator) 70 | { 71 | if (validator == null) 72 | { 73 | throw new ArgumentNullException(nameof(validator)); 74 | } 75 | concurrentDictionary.AddOrUpdate(idLength, k => validator, (k, a) => validator); 76 | } 77 | /// 78 | /// 添加默认已提供的对应实现,用于临时解决core下可能会出现的反射错误 79 | /// 80 | public static void ResetDefaultValidator() 81 | { 82 | concurrentDictionary.AddOrUpdate((int)IDLength.Fifteen, k => new ID15Validator(), (k, a) => new ID15Validator()); 83 | concurrentDictionary.AddOrUpdate((int)IDLength.Eighteen, k => new ID18Validator(), (k, a) => new ID18Validator()); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/NumberValidators/IdentityCards/Validators/IIDValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.IdentityCards.Validators 7 | { 8 | /// 9 | /// 身份证验证接口 10 | /// 11 | public interface IIDValidator : IValidator 12 | { 13 | /// 14 | /// 用于验证的字典数据 15 | /// 16 | IValidationDictionary Dictionary { get; set; } 17 | /// 18 | /// 生成身份证号码 19 | /// 20 | /// 行政区划编号 21 | /// 出生日期 22 | /// 顺序号 23 | /// 24 | string GenerateID(int areaNumber, DateTime birthDay, int sequenceNumber); 25 | /// 26 | /// 验证身份证是否正确 27 | /// 28 | /// 待验证的证件号码 29 | /// 允许最小年份,默认0 30 | /// 验证区域级别,默认AreaValidLimit.Province 31 | /// 是否忽略校验位验证,默认false 32 | /// 验证结果 33 | IDValidationResult Validate(string idNumber, ushort minYear = 0, AreaValidLimit validLimit = AreaValidLimit.Province, bool ignoreCheckBit = false); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/AmountVersion.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices 7 | { 8 | /// 9 | /// 金额版本号,仅10位发票代码有 10 | /// 11 | public enum AmountVersion 12 | { 13 | /// 14 | /// 电脑开票 15 | /// 16 | Computer = 0, 17 | /// 18 | /// 手写万元版 19 | /// 20 | TenThousand = 1, 21 | /// 22 | /// 手写十万元版 23 | /// 24 | OneHundredThousand = 2, 25 | /// 26 | /// 手写百万元版 27 | /// 28 | Million = 3, 29 | /// 30 | /// 手写千万元版 31 | /// 32 | TenMillion = 4 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/GBT2260OnlyProvince.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices 7 | { 8 | /// 9 | /// 仅包含省、直辖市以及自治区的行政区划代码 10 | /// 11 | public class GBT2260OnlyProvince : IValidationDictionary 12 | { 13 | private GBT2260OnlyProvince() { } 14 | /// 15 | /// 单例 16 | /// 17 | public static readonly GBT2260OnlyProvince Singleton = new GBT2260OnlyProvince(); 18 | 19 | //所有支持区域可从航信官网对比 http://www.aisino.com/links.asp 20 | static readonly Dictionary Dictionary = new Dictionary 21 | { 22 | #region 区域代码 23 | { 1100,"北京市"}, 24 | { 1200,"天津市"}, 25 | { 1300,"河北省"}, 26 | { 1400,"山西省"}, 27 | { 1500,"内蒙古自治区"}, 28 | { 2100,"辽宁省"}, 29 | { 2102,"大连市"}, 30 | { 2200,"吉林省"}, 31 | { 2300,"黑龙江省"}, 32 | { 3100,"上海市"}, 33 | { 3200,"江苏省"}, 34 | { 3300,"浙江省"}, 35 | { 3302,"宁波市"}, 36 | { 3400,"安徽省"}, 37 | { 3500,"福建省"}, 38 | { 3502,"厦门市"}, 39 | { 3600,"江西省"}, 40 | { 3700,"山东省"}, 41 | { 3702,"青岛市"}, 42 | { 4100,"河南省"}, 43 | { 4200,"湖北省"}, 44 | { 4300,"湖南省"}, 45 | { 4400,"广东省"}, 46 | { 4403,"深圳市"}, 47 | { 4500,"广西壮族自治区"}, 48 | { 4600,"海南省"}, 49 | { 5000,"重庆市"}, 50 | { 5100,"四川省"}, 51 | { 5200,"贵州省"}, 52 | { 5300,"云南省"}, 53 | { 5400,"西藏自治区"}, 54 | { 6100,"陕西省"}, 55 | { 6200,"甘肃省"}, 56 | { 6300,"青海省"}, 57 | { 6400,"宁夏回族自治区"}, 58 | { 6500,"新疆维吾尔自治区"}, 59 | //{ 7100,"台湾省"}, 60 | //{ 8100,"香港特别行政区"}, 61 | //{ 8200,"澳门特别行政区"}, 62 | #endregion 63 | }; 64 | /// 65 | /// 获取字典 66 | /// 67 | /// 68 | public IDictionary GetDictionary() 69 | { 70 | return Dictionary; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/VATCodeValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices 7 | { 8 | /// 9 | /// 增值税发票代码验证结果 10 | /// 11 | public class VATCodeValidationResult : ValidationResult 12 | { 13 | /// 14 | /// 号码长度 15 | /// 16 | public VATLength VATLength { get; internal set; } 17 | /// 18 | /// 行政区划代码 19 | /// 20 | public int AreaNumber { get; internal set; } 21 | /// 22 | /// 行政区域名称 23 | /// 24 | public string AreaName { get; internal set; } 25 | /// 26 | /// 发票类型 27 | /// 28 | public VATKind? Category { get; internal set; } 29 | /// 30 | /// 印刷年份 31 | /// 32 | public int Year { get; internal set; } 33 | /// 34 | /// 印刷批次 35 | /// 36 | public int Batch { get; internal set; } 37 | /// 38 | /// 发票联次,仅10位长度和12位长度折叠票发票、区块链电子发票才有 39 | /// 40 | public int DuplicateNumber { get; internal set; } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/VATKind.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices 7 | { 8 | /// 9 | /// 增值税发票类别,与Aisino定义一致 10 | /// 11 | public enum VATKind 12 | { 13 | /// 14 | /// 增值税专用发票 15 | /// 16 | Special = 0, 17 | /// 18 | /// 增值税普通发票(纸质非卷票) 19 | /// 20 | Plain = 2, 21 | /// 22 | /// 货物运输业增值税专用发票(20160701后已停用 http://www.chinatax.gov.cn/n810341/n810755/c1983655/content.html) 23 | /// 24 | Transport = 11, 25 | /// 26 | /// 增值税普通发票(卷票) 27 | /// 28 | Roll = 41, 29 | /// 30 | /// 增值税电子发票 31 | /// 32 | Electronic = 51, 33 | /// 34 | /// 区块链电子发票 35 | /// 36 | Blockchain = 71, 37 | } 38 | /// 39 | /// 增值税电子发票细分类型 40 | /// 41 | public enum ElectronicVATKind 42 | { 43 | /// 44 | /// 普通的增值税电子发票 45 | /// 46 | Normal = 11, 47 | /// 48 | /// 收费公路通行费 49 | /// 50 | TollRoad = 12, 51 | /// 52 | /// 电子专票 53 | /// 54 | Special = 13, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/VATLength.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices 7 | { 8 | /// 9 | /// 增值税发票号码长度 10 | /// 11 | public enum VATLength 12 | { 13 | /// 14 | /// 10位长度 15 | /// 16 | Ten = 10, 17 | /// 18 | /// 12位长度 19 | /// 20 | Twelve = 12 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/ErrorMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices.Validators 7 | { 8 | /// 9 | /// 错误描述类 10 | /// 11 | internal static class ErrorMessage 12 | { 13 | /// 14 | /// 发票代码为空 15 | /// 16 | public const string Empty = "发票代码为空"; 17 | /// 18 | /// 错误的发票代码 19 | /// 20 | public const string Error = "错误的发票代码"; 21 | /// 22 | /// 发票年份超出允许的年份范围 23 | /// 24 | public const string YearOutOfRange = "发票年份超出允许的年份范围{0} ~ {1}"; 25 | /// 26 | /// 发票发行区域识别失败 27 | /// 28 | public const string InvalidArea = "发票发行区域识别失败"; 29 | /// 30 | /// 无效的发票类别 31 | /// 32 | public const string InvalidKind = "无效的发票类别"; 33 | /// 34 | /// 发票类别错误,无法生成发票代码 35 | /// 36 | public const string GenerateWrongKind = "发票类别错误,无法生成发票代码"; 37 | /// 38 | /// 无效实现 39 | /// 40 | public const string InvalidImplement = "未能找到或无效的 {0} 位发票代码实现"; 41 | /// 42 | /// 长度不符 43 | /// 44 | public const string LengthOutOfRange = "发票代码非 {0} 位"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/IVATCodeValidator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Invoices.Validators 7 | { 8 | /// 9 | /// 增值税发票代码验证接口 10 | /// 11 | public interface IVATCodeValidator : IValidator 12 | where TResult : VATCodeValidationResult, new() 13 | { 14 | /// 15 | /// 用于验证的字典数据 16 | /// 17 | IValidationDictionary Dictionary { get; set; } 18 | /// 19 | /// 生成增值税发票代码 20 | /// 21 | /// 行政区划 22 | /// 年份 23 | /// 批次 24 | /// 要生成的发票类型 25 | /// 如果发票种类为电子发票时,要生成的电子发票细分类型 26 | /// 27 | string GenerateVATCode(int areaNumber, ushort year, ushort batch, VATKind kind, ElectronicVATKind? electKind = null); 28 | /// 29 | /// 发票代码验证 30 | /// 31 | /// 待验证的发票代码 32 | /// 要验证的发票类型,不指定则传null 33 | /// 允许的最小年份(注:2012年1月1日营改增开始上海试点) 34 | /// 35 | TResult Validate(string vatCode, VATKind? kind = null, ushort minYear = 2012); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCode10ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Invoices.Validators 6 | { 7 | /// 8 | /// 增值税发票和普通(纸质)专有的验证结果 9 | /// 10 | public class VATCode10ValidationResult : VATCodeValidationResult 11 | { 12 | /// 13 | /// 发票金额版本号,仅10位长度发票才有 14 | /// 15 | public AmountVersion AmountVersion { get; internal set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCode10Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace NumberValidators.Invoices.Validators 8 | { 9 | /// 10 | /// 增值税普通/专用发票代码验证(营改增之后的规则) 11 | /// 12 | public class VATCode10Validator : VATCodeValidator 13 | { 14 | /*1-4区域编码 15 | * 5-6年份 16 | * 7印制批次 17 | * 8发票类别(3/6 增值税普通发票,1/5 增值税专用发票,7/2 货物运输业增值税专用发票) 18 | * 9联次(发票共有几联) 19 | * 10金额版本号(1:万元版,2:十万元版,3:百万元版,4:千万元版,0:电脑发票)*/ 20 | private static readonly SortedDictionary _kindDic = new SortedDictionary 21 | { 22 | {'3',VATKind.Plain }, 23 | {'6',VATKind.Plain}, 24 | {'1',VATKind.Special}, 25 | {'5',VATKind.Special}, 26 | {'2',VATKind.Transport}, 27 | {'7',VATKind.Transport}, 28 | }; 29 | private static readonly Dictionary _duplicateDic = new Dictionary 30 | { 31 | {VATKind.Plain ,2}, 32 | {VATKind.Special ,3}, 33 | {VATKind.Transport ,3}, 34 | }; 35 | /// 36 | /// 号码长度 37 | /// 38 | public override VATLength VATLength => VATLength.Ten; 39 | /// 40 | /// 支持的增值税发票类型 41 | /// 42 | protected override IEnumerable SupportKind => _duplicateDic.Keys; 43 | /// 44 | /// 验证用的正则 45 | /// 46 | protected override string RegexPattern => RegexPatterns.VATCode10; 47 | /// 48 | /// 生成增值税发票代码 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// 54 | /// 如果发票种类为电子发票时,要生成的电子发票细分类型 55 | /// 56 | protected override string GenerateVATCode(string areaNumber, string year, ushort batch, VATKind kind, ElectronicVATKind? electKind) 57 | { 58 | var query = _kindDic.Where(kv => kv.Value == kind); 59 | if (!query.Any()) 60 | { 61 | throw new NotSupportedException(ErrorMessage.GenerateWrongKind); 62 | } 63 | var rdKind = query.First().Key; 64 | return string.Format("{0}{1}{2}{3}{4}0", areaNumber, year, (batch % 10).ToString(), rdKind, _duplicateDic[kind]); 65 | } 66 | /// 67 | /// 获取年份 68 | /// 69 | /// 70 | /// 71 | protected override int GetYear(string vatCode) 72 | { 73 | return int.Parse(vatCode.Substring(4, 2)) + 2000; 74 | } 75 | /// 76 | /// 获取行政区划 77 | /// 78 | /// 79 | /// 80 | protected override int GetAreaNumber(string vatCode) 81 | { 82 | return int.Parse(vatCode.Substring(0, 4)); 83 | } 84 | /// 85 | /// 验证类型是否符合 86 | /// 87 | /// 88 | /// 89 | /// 90 | /// 91 | protected override bool ValidVATKind(string vatCode, VATKind? kind, VATCode10ValidationResult result) 92 | { 93 | var valid = _kindDic.ContainsKey(vatCode[7]) && (!kind.HasValue || kind.Value == _kindDic[vatCode[7]]); 94 | if (!valid) 95 | { 96 | result.AddErrorMessage(ErrorMessage.InvalidKind); 97 | } 98 | else 99 | { 100 | result.Category = _kindDic[vatCode[7]]; 101 | } 102 | return valid; 103 | } 104 | /// 105 | /// 验证填充额外信息 106 | /// 107 | /// 108 | /// 109 | /// 110 | protected override bool ValidOtherInfo(string vatCode, VATCode10ValidationResult result) 111 | { 112 | result.DuplicateNumber = int.Parse(vatCode.Substring(8, 1)); 113 | result.AmountVersion = (AmountVersion)int.Parse(vatCode.Substring(9, 1)); 114 | return base.ValidOtherInfo(vatCode, result); 115 | } 116 | /// 117 | /// 获取批次 118 | /// 119 | /// 120 | /// 121 | protected override int GetBatch(string vatCode) 122 | { 123 | return int.Parse(vatCode.Substring(7, 1)); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCode12ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Invoices.Validators 6 | { 7 | /// 8 | /// 除增值税专项发票外的验证结果 9 | /// 10 | public class VATCode12ValidationResult : VATCodeValidationResult 11 | { 12 | /// 13 | /// 增值税电子发票细分类型 14 | /// 15 | public ElectronicVATKind? ElectronicVATKind { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCode12Validator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace NumberValidators.Invoices.Validators 8 | { 9 | /// 10 | /// 增值税电子/卷票发票代码验证 11 | /// 电子发票规则参考 http://www.chinatax.gov.cn/n810341/n810755/c1919901/content.html 12 | /// 卷票规则参考 http://www.chinatax.gov.cn/n810341/n810755/c2420199/content.html 13 | /// 收费公路通行费增值税电子普通发票规则参考 http://www.chinatax.gov.cn/n810341/n810755/c2985595/content.html 14 | /// 定额发票虽然是12位,但根据《全面推开营改增试点工作(发票)2016年第8号——关于明确通用定额发票使用有关问题的通知》2017.01.01后只有提供车辆停放服务的纳税人、起征点以下的纳税人才可以继续使用定额发票,所以此处不予支持(https://wenku.baidu.com/view/12d624c2d4d8d15abf234e12.html) 15 | /// 区块链电子普通发票的发票代码 例如144031809110,第6-7位为年份,第8位0代表行业种类为通用类、第9位9代表深圳电子普通发票专属种类类别,第10位代表批次,第11位代表联次,第12位0代表无限制金额版 http://www.360doc.com/content/18/0905/12/12373774_784061533.shtml 16 | /// 电子专票的发票代码为12位,编码规则:第1位为0,第2-5位代表省、自治区、直辖市和计划单列市,第6-7位代表年度,第8-10位代表批次,第11-12位为13。发票号码为8位,按年度、分批次编制 17 | /// 18 | public class VATCode12Validator : VATCodeValidator 19 | { 20 | /* 第1位为0或1 1为区块链发票 0为电子发票或卷票 21 | * 第2-5位代表省、自治区、直辖市和计划单列市 22 | * 第6-7位代表年度 23 | * 第8-10位代表批次 24 | * 第11-12位代表票种和规格/联次 25 | ** (11代表增值税电子普通发票, 26 | ** 12代表收费公路通行费增值税电子普通发票,注意通行费发票同专票一样可以进行发票抵扣,但发票查验时还是通过校验码查询, 27 | * 13代表增值税电子专票 28 | ** 06代表57mm×177.8mm增值税普通发票(卷票),07代表76mm×177.8mm增值税普通发票(卷票), 29 | ** 04代表二联增值税普通发票(折叠票),05代表五联增值税普通发票(折叠票)) 30 | * 发票号码为8位,按年度、分批次编制。*/ 31 | private static readonly Dictionary _kindDic = new Dictionary 32 | { 33 | {"11",VATKind.Electronic }, 34 | {"12",VATKind.Electronic }, 35 | {"13",VATKind.Electronic }, 36 | {"06",VATKind.Roll}, 37 | {"07",VATKind.Roll}, 38 | {"04",VATKind.Plain}, 39 | {"05",VATKind.Plain}, 40 | }; 41 | /// 42 | /// 号码长度 43 | /// 44 | public override VATLength VATLength => VATLength.Twelve; 45 | /// 46 | /// 支持的增值税发票类型 47 | /// 48 | protected override IEnumerable SupportKind => _kindDic.Values.Distinct(); 49 | /// 50 | /// 验证用的正则 51 | /// 52 | protected override string RegexPattern => RegexPatterns.VATCode12; 53 | /// 54 | /// 生成增值税发票代码(注意不支持生成区块链发票) 55 | /// 56 | /// 57 | /// 58 | /// 59 | /// 60 | /// 如果发票种类为电子发票时,要生成的电子发票细分类型 61 | /// 62 | protected override string GenerateVATCode(string areaNumber, string year, ushort batch, VATKind kind, ElectronicVATKind? electKind) 63 | { 64 | if (electKind.HasValue && kind != VATKind.Electronic) 65 | { 66 | throw new ArgumentException($"{nameof(kind)} must be 'Electronic' while {nameof(electKind)} exist"); 67 | } 68 | var query = _kindDic.Where(kv => kv.Value == kind); 69 | if (!query.Any()) 70 | { 71 | throw new NotSupportedException(ErrorMessage.GenerateWrongKind); 72 | } 73 | var rdKind = query.OrderBy(g => Guid.NewGuid()).First().Key; 74 | if (electKind.HasValue) 75 | { 76 | rdKind = Convert.ToInt32(electKind).ToString(); 77 | } 78 | return string.Format("0{0}{1}{2}{3}", areaNumber, year, (batch % 1000).ToString().PadLeft(3, '0'), rdKind); 79 | } 80 | /// 81 | /// 获取年份 82 | /// 83 | /// 84 | /// 85 | protected override int GetYear(string vatCode) 86 | { 87 | return int.Parse(vatCode.Substring(5, 2)) + 2000; 88 | } 89 | /// 90 | /// 获取行政区划 91 | /// 92 | /// 93 | /// 94 | protected override int GetAreaNumber(string vatCode) 95 | { 96 | return int.Parse(vatCode.Substring(1, 4)); 97 | } 98 | /// 99 | /// 区域校验时是否忽略34两位行政区划编码 100 | /// 101 | /// 102 | /// 103 | protected override bool AreaValidSkip34(VATKind kind) 104 | { 105 | if (kind == VATKind.Electronic) 106 | {//电子发票行政区划可能会具体到市级,吉林、安徽、山东、湖北 都发现具体到市级行政编号的情况,所以电子发票支持只查前2位行政区划 107 | return true; 108 | } 109 | return base.AreaValidSkip34(kind); 110 | } 111 | /// 112 | /// 验证类型是否符合 113 | /// 114 | /// 115 | /// 116 | /// 117 | /// 118 | protected override bool ValidVATKind(string vatCode, VATKind? kind, VATCode12ValidationResult result) 119 | { 120 | if (vatCode[0] == '1') 121 | { 122 | //区块链发票以1开头 123 | return this.ValidVATKindWithBlockchain(vatCode, kind, result); 124 | } 125 | else 126 | { 127 | //增值税发票以0开头 128 | return this.ValidVATKindWithoutBlockchain(vatCode, kind, result); 129 | } 130 | } 131 | private bool ValidVATKindWithBlockchain(string vatCode, VATKind? kind, VATCode12ValidationResult result) 132 | { 133 | //区块链发票以1开头 134 | if (vatCode[11] == '0' && (!kind.HasValue || kind.Value == VATKind.Blockchain)) 135 | { 136 | result.Category = VATKind.Blockchain; 137 | result.DuplicateNumber = int.Parse(vatCode[10].ToString()); 138 | return true; 139 | } 140 | result.AddErrorMessage(ErrorMessage.InvalidKind); 141 | return false; 142 | } 143 | private bool ValidVATKindWithoutBlockchain(string vatCode, VATKind? kind, VATCode12ValidationResult result) 144 | { 145 | //增值税发票以0开头 146 | var key = vatCode.Substring(10, 2); 147 | var valid = _kindDic.ContainsKey(key) && (!kind.HasValue || kind.Value == _kindDic[key]); 148 | if (!valid) 149 | { 150 | result.AddErrorMessage(ErrorMessage.InvalidKind); 151 | } 152 | else 153 | { 154 | result.Category = _kindDic[key]; 155 | switch (result.Category) 156 | { 157 | case VATKind.Plain: 158 | result.DuplicateNumber = key == "04" ? 2 : 5; 159 | break; 160 | case VATKind.Electronic: 161 | if (Enum.TryParse(key, out ElectronicVATKind eKind)) 162 | { 163 | result.ElectronicVATKind = eKind; 164 | } 165 | break; 166 | default: break; 167 | } 168 | } 169 | return valid; 170 | } 171 | /// 172 | /// 获取批次 173 | /// 174 | /// 175 | /// 176 | protected override int GetBatch(string vatCode) 177 | { 178 | if (vatCode[0] == '0') 179 | { 180 | //增值税发票 181 | return int.Parse(vatCode.Substring(7, 3)); 182 | } 183 | else 184 | { 185 | //区块链电子发票 186 | return int.Parse(vatCode[9].ToString()); 187 | } 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCodeValidator.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace NumberValidators.Invoices.Validators 8 | { 9 | /// 10 | /// 增值税发票验证类 11 | /// 12 | public abstract class VATCodeValidator : BaseValidatorWithDictionary, IVATCodeValidator 13 | where TResult : VATCodeValidationResult, new() 14 | { 15 | #region props 16 | /// 17 | /// 号码长度 18 | /// 19 | public abstract VATLength VATLength { get; } 20 | /// 21 | /// 默认基础数据字典 22 | /// 23 | protected override IValidationDictionary DefaultDictionary => GBT2260OnlyProvince.Singleton; 24 | /// 25 | /// 支持的增值税发票类型 26 | /// 27 | protected abstract IEnumerable SupportKind { get; } 28 | /// 29 | /// 空错误提示 30 | /// 31 | protected override string EmptyErrorMessage => ErrorMessage.Empty; 32 | /// 33 | /// 正则验证失败错误提示 34 | /// 35 | protected override string RegexMatchFailMessage => ErrorMessage.Error; 36 | #endregion 37 | 38 | #region interface 39 | /// 40 | /// 生成随机发票代码 41 | /// 42 | /// 43 | public override string GenerateRandomNumber() 44 | { 45 | var areaNumber = this.Dictionary.GetDictionary().Keys.OrderBy(g => Guid.NewGuid()).FirstOrDefault(i => i >= 10 && i < 10000); 46 | if (areaNumber == 0) 47 | { 48 | throw new ArgumentException("GB2312 dictionary is not correct."); 49 | } 50 | var yearNow = DateTime.Now.Year; 51 | var year = yearNow - RandomHelper.GetRandomNumber(yearNow - 2012); 52 | var batch = RandomHelper.GetRandomNumber(1000); 53 | return this.GenerateVATCode(areaNumber, (ushort)year, (ushort)batch, SupportKind.OrderBy(g => Guid.NewGuid()).First()); 54 | } 55 | /// 56 | /// 按输入生成发票代码 57 | /// 58 | /// 行政区划代码 59 | /// 发票年份 60 | /// 批次 61 | /// 发票类型 62 | /// 如果发票种类为电子发票时,要生成的电子发票细分类型 63 | /// 64 | public virtual string GenerateVATCode(int areaNumber, ushort year, ushort batch, VATKind kind, ElectronicVATKind? electKind = null) 65 | { 66 | if (areaNumber < 10 || areaNumber > 9999) 67 | { 68 | throw new ArgumentException("argument error"); 69 | } 70 | return this.GenerateVATCode(areaNumber.ToString().PadRight(4, '0'), (year % 100).ToString().PadLeft(2, '0'), batch, kind, electKind); 71 | } 72 | /// 73 | /// 按输入生成发票代码 74 | /// 75 | /// 76 | /// 77 | /// 78 | /// 79 | /// 如果发票种类为电子发票时,要生成的电子发票细分类型 80 | /// 81 | protected abstract string GenerateVATCode(string areaNumber, string year, ushort batch, VATKind kind, ElectronicVATKind? electKind); 82 | /// 83 | /// 验证发票代码是否正确 84 | /// 85 | /// 86 | /// 87 | public override TResult Validate(string number) 88 | { 89 | return this.Validate(number, minYear: 2012); 90 | } 91 | /// 92 | /// 验证发票代码是否正确 93 | /// 94 | /// 发票代码 95 | /// 发票类型 96 | /// 最小年份 97 | /// 98 | public virtual TResult Validate(string vatCode, VATKind? kind = null, ushort minYear = 2012) 99 | { 100 | var result = base.Validate(vatCode); 101 | var valid = result.IsValid 102 | && this.ValidYear(result.Number, minYear, result) 103 | && this.ValidVATKind(result.Number, kind, result) 104 | && this.ValidArea(result.Number, result) 105 | && this.ValidOtherInfo(result.Number, result); 106 | if (valid) 107 | { 108 | result.VATLength = this.VATLength; 109 | } 110 | return result; 111 | } 112 | #endregion 113 | 114 | #region methods 115 | private bool ValidYear(string vatCode, ushort minYear, TResult result) 116 | { 117 | var year = this.GetYear(vatCode); 118 | var yearNow = DateTime.Now.Year; 119 | var valid = year >= minYear && year <= yearNow; 120 | result.Year = year; 121 | if (!valid) 122 | { 123 | result.AddErrorMessage(ErrorMessage.YearOutOfRange, minYear, yearNow); 124 | } 125 | return valid; 126 | } 127 | /// 128 | /// 获取发票年份 129 | /// 130 | /// 131 | /// 132 | protected abstract int GetYear(string vatCode); 133 | private bool ValidArea(string vatCode, TResult result) 134 | { 135 | var areaNumber = this.GetAreaNumber(vatCode); 136 | var dic = this.Dictionary.GetDictionary(); 137 | var valid = dic.ContainsKey(areaNumber); 138 | result.AreaNumber = areaNumber; 139 | if (!valid && this.AreaValidSkip34(result.Category.Value)) 140 | { 141 | areaNumber = areaNumber / 100 * 100; 142 | valid = dic.ContainsKey(areaNumber); 143 | } 144 | if (!valid) 145 | { 146 | result.AddErrorMessage(ErrorMessage.InvalidArea); 147 | } 148 | else 149 | { 150 | result.AreaName = dic[areaNumber]; 151 | } 152 | return valid; 153 | } 154 | /// 155 | /// 区域校验时是否忽略34两位行政区划编码 156 | /// 157 | protected virtual bool AreaValidSkip34(VATKind kind) 158 | { 159 | return false; 160 | } 161 | /// 162 | /// 获取行政区划代码 163 | /// 164 | /// 165 | /// 166 | protected abstract int GetAreaNumber(string vatCode); 167 | /// 168 | /// 验证发票类型是否正确 169 | /// 170 | /// 171 | /// 172 | /// 173 | /// 174 | protected abstract bool ValidVATKind(string vatCode, VATKind? kind, TResult result); 175 | /// 176 | /// 验证填充额外信息 177 | /// 178 | /// 179 | /// 180 | /// 181 | protected virtual bool ValidOtherInfo(string vatCode, TResult result) 182 | { 183 | result.Batch = this.GetBatch(vatCode); 184 | return true; 185 | } 186 | /// 187 | /// 获取发票批次 188 | /// 189 | protected abstract int GetBatch(string vatCode); 190 | #endregion 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/NumberValidators/Invoices/Validators/VATCodeValidatorHelper.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace NumberValidators.Invoices.Validators 8 | { 9 | /// 10 | /// 增值税发票验证帮助类 11 | /// 12 | public static class VATCodeValidatorHelper 13 | { 14 | private static readonly ConcurrentDictionary> concurrentDictionary 15 | = new ConcurrentDictionary>(); 16 | 17 | static VATCodeValidatorHelper() 18 | { 19 | ResetDefaultValidator(); 20 | } 21 | 22 | /// 23 | /// 验证当前增值税发票代码是否正确 24 | /// 25 | /// 发票代码 26 | /// 发票类型 27 | /// 发票长度 28 | /// 最小年份 29 | /// 30 | public static VATCodeValidationResult Validate(string vatCode, VATKind? kind = null, int? length = null, ushort minYear = 2012) 31 | { 32 | IVATCodeValidator validator = null; 33 | _ = ValidatorHelper.ValidEmpty(vatCode, out VATCodeValidationResult result, ErrorMessage.Empty) 34 | && ValidatorHelper.ValidLength(vatCode, length, ErrorMessage.LengthOutOfRange, result) 35 | && ValidImplement(vatCode, result, out validator); 36 | return validator == null ? result : validator.Validate(vatCode, kind, minYear); 37 | } 38 | 39 | private static bool ValidImplement(string code, VATCodeValidationResult result, out IVATCodeValidator validator) 40 | { 41 | _ = concurrentDictionary.TryGetValue(code.Length, out validator) 42 | || ValidatorHelper.ValidImplement(code, result, "VATCode{0}Validator", ErrorMessage.InvalidImplement, out validator, typeof(IVATCodeValidator<>)); 43 | return validator != null; 44 | } 45 | 46 | /// 47 | /// 设置默认的校验规则 48 | /// 49 | /// 默认校验实现对应的编号长度 50 | /// 默认实现 51 | public static void SetValidator(int vatLength, IVATCodeValidator validator) 52 | { 53 | if (validator == null) 54 | { 55 | throw new ArgumentNullException(nameof(validator)); 56 | } 57 | concurrentDictionary.AddOrUpdate(vatLength, k => validator, (k, a) => validator); 58 | } 59 | /// 60 | /// 添加默认已提供的对应实现,用于临时解决core下可能会出现的反射错误 61 | /// 62 | public static void ResetDefaultValidator() 63 | { 64 | concurrentDictionary.AddOrUpdate((int)VATLength.Ten, k => new VATCode10Validator(), (k, a) => new VATCode10Validator()); 65 | concurrentDictionary.AddOrUpdate((int)VATLength.Twelve, k => new VATCode12Validator(), (k, a) => new VATCode12Validator()); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/NumberValidators/NumberValidators.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0;net40 5 | dong fang 6 | 中国大陆证件、发票等有国家规定标准的验证类库 7 | https://github.com/fdstar/NumberValidators 8 | https://mit-license.org/ 9 | 10 | 11 | 12 | bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml 13 | 1.0.3 14 | 15 | 16 | 17 | NETSTANDARD2_0 18 | 19 | 20 | 21 | NET40 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/AreaHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Utils 6 | { 7 | /// 8 | /// 行政区划帮助类 9 | /// 10 | public static class AreaHelper 11 | { 12 | /// 13 | /// 根据行政编号获取最深的行政区划信息(可根据Parent获取其父级区划),注意其转化为字符串长度必须为偶数 14 | /// 15 | /// 16 | /// 17 | /// 18 | public static Area GetDeepestArea(int code, IValidationDictionary dictionary) 19 | { 20 | //按GBT2260 - 2007版本说明,已撤销移除的区域编号不会被其它地方使用,那么完全可以只需要GBT2260基类,然后将已移除的行政区划加入Dictonary即可 21 | //否则的话,可以每期GBT2260标准都如现在一样,设置对应的类,然后按出生日期确定算法从这些集合中找到对应的区域编号 22 | Area area = null; 23 | Area lastArea = null; 24 | var dic = dictionary?.GetDictionary(); 25 | if (dic == null) 26 | { 27 | throw new ArgumentNullException(nameof(dictionary)); 28 | } 29 | while (code > 0) 30 | { 31 | if (code < 10) 32 | { 33 | throw new ArgumentException("行政区划代码错误"); 34 | } 35 | //在这里才做if判断是为了防止因为GBT2260标准变化导致的区域id无法获取的情况 36 | if (dic.ContainsKey(code)) 37 | { 38 | var tmpArea = new Area(code, dic[code]); 39 | if (area == null) 40 | { 41 | area = tmpArea; 42 | } 43 | else 44 | { 45 | lastArea.Parent = tmpArea; 46 | } 47 | lastArea = tmpArea; 48 | } 49 | code /= 100; 50 | } 51 | return area; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/GBT/GBT11714_1997.cs: -------------------------------------------------------------------------------- 1 | using NumberValidators.Utils.ISO; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Text.RegularExpressions; 7 | 8 | namespace NumberValidators.Utils.GBT 9 | { 10 | /// 11 | /// 国标GB/T 11714-1997 12 | /// 13 | public static class GBT11714_1997 14 | { 15 | /// 16 | /// 加权因子 17 | /// 18 | private static readonly int[] WeightingFactors = { 3, 7, 9, 10, 5, 8, 4, 2 }; 19 | /// 20 | /// 校验码 21 | /// 22 | private static readonly char[] CheckBits = new char[11]; 23 | /// 24 | /// 本体代码及其对应的代码字符数值 25 | /// 26 | private static readonly Dictionary CodeDictionary = new Dictionary(); 27 | static GBT11714_1997() 28 | { 29 | for (var i = 0; i <= 35; i++) 30 | { 31 | var c = (char)((i > 9 ? 55 : 48) + i); 32 | CodeDictionary.Add(c, i); 33 | } 34 | for (var i = 0; i < 11; i++) 35 | { 36 | char c = (char)(48 + i); 37 | if (i == 10) { c = 'X'; } 38 | CheckBits[i] = c; 39 | } 40 | } 41 | /// 42 | /// 获取校验码 43 | /// 44 | /// 组织机构代码前八位,注意必须大写字母或数字,如超出8位也只取前8位 45 | /// 46 | public static char GetCheckBit(string code) 47 | { 48 | if (code == null || !Regex.IsMatch(code, @"^[0-9A-Z]{8,}$")) 49 | { 50 | throw new ArgumentException("Error code."); 51 | } 52 | var mod = (11 - ISO7064_1983.MOD_11_2(code.Select(c => CodeDictionary[c]).Take(8).ToArray(), WeightingFactors, 11)) % 11; 53 | return CheckBits[mod]; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/GBT/GBT17710_1999.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Utils.GBT 6 | { 7 | /// 8 | /// 国标GB/T 17710-1999 9 | /// 10 | public static class GBT17710_1999 11 | { 12 | /// 13 | /// 按GB/T 17710-1999中定义的ISO 7064 MOD 11,10算法 14 | /// 15 | /// 16 | /// 17 | public static int MOD_11_10(int[] source) 18 | { 19 | int p = 10; 20 | for (var i = 0; i < source.Length; i++) 21 | { 22 | int s = (source[i] + p) % 10 * 2; 23 | p = (s == 0 ? 20 : s) % 11; 24 | } 25 | return (11 - p) % 10; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/GBT/GBT2260.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Utils.GBT 7 | { 8 | /// 9 | /// GBT2260标准,目前分别有以下10个版本:1980,1982,1984,1986,1988,1991,1995,1999,2002,2007 等等 10 | /// 第一代身份证办理时用的是1984版本…… 11 | /// 12 | public abstract class GBT2260 : IValidationDictionary 13 | { 14 | /// 15 | /// 获取数据字典 16 | /// 17 | /// 18 | public abstract IDictionary GetDictionary(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/GBT/GBT2659_2000OfDigitalCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Utils.GBT 7 | { 8 | /// 9 | /// 世界各国和地区名称代码 (GB/T 2659-2000) 10 | /// 11 | public class GBT2659_2000OfDigitalCode : IValidationDictionary 12 | { 13 | private GBT2659_2000OfDigitalCode() { } 14 | /// 15 | /// 单例 16 | /// 17 | public static readonly GBT2659_2000OfDigitalCode Singleton = new GBT2659_2000OfDigitalCode(); 18 | /// 19 | /// 基础数据字典 20 | /// 21 | private Dictionary Dictionary; 22 | private static object _lockObj = new object(); 23 | /// 24 | /// 获取字典 25 | /// 26 | /// 27 | public IDictionary GetDictionary() 28 | { 29 | if (Dictionary == null) 30 | { 31 | lock (_lockObj) 32 | { 33 | if (Dictionary == null) 34 | { 35 | Dictionary = NationCode.NationCodes.Value.ToDictionary(c => c.DigitalCode, c => c); 36 | } 37 | } 38 | } 39 | return Dictionary; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/GBT/NationCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Utils.GBT 6 | { 7 | /// 8 | /// 世界各国和地区名称代码 9 | /// 10 | public class NationCode 11 | { 12 | /// 13 | /// 世界各国和地区名称代码基础数据 (GB/T 2659-2000) 14 | /// 15 | public static Lazy NationCodes 16 | { 17 | get 18 | { 19 | return new Lazy(() => 20 | { 21 | return new NationCode[] { 22 | #region 基础数据 23 | new NationCode{ChineseAbbr="阿富汗",EnglishAbbr="AFGHANISTAN",TwoCharCode="AF",ThreeCharCode="AFG",DigitalCode="004",FullNameOfCHS="阿富汗伊斯兰国",FullNameOfENG="Islamic State ofAfghanistan"}, 24 | new NationCode{ChineseAbbr="阿尔巴尼亚",EnglishAbbr="ALBANIA",TwoCharCode="AL",ThreeCharCode="ALB",DigitalCode="008",FullNameOfCHS="阿尔马尼亚共和国",FullNameOfENG="Republic ofAlbania"}, 25 | new NationCode{ChineseAbbr="阿尔及利亚",EnglishAbbr="ALGERIA",TwoCharCode="DZ",ThreeCharCode="DZA",DigitalCode="012",FullNameOfCHS="阿尔及利亚民主人民共和国",FullNameOfENG="Democratic People's Republic of Algeria"}, 26 | new NationCode{ChineseAbbr="美属萨摩亚",EnglishAbbr="AMERICAN SAMOA",TwoCharCode="AS",ThreeCharCode="ASM",DigitalCode="016",FullNameOfCHS="美属萨摩亚",FullNameOfENG="American Samoa"}, 27 | new NationCode{ChineseAbbr="安道尔",EnglishAbbr="ANDORRA",TwoCharCode="AD",ThreeCharCode="AND",DigitalCode="020",FullNameOfCHS="安道尔公国",FullNameOfENG="Principality of Andorra"}, 28 | new NationCode{ChineseAbbr="安哥拉",EnglishAbbr="ANGOLA",TwoCharCode="AO",ThreeCharCode="AGO",DigitalCode="024",FullNameOfCHS="安哥拉共和国",FullNameOfENG="Republic of Angola"}, 29 | new NationCode{ChineseAbbr="安圭拉",EnglishAbbr="ANGUILLA",TwoCharCode="AI",ThreeCharCode="AIA",DigitalCode="660",FullNameOfCHS="安圭拉",FullNameOfENG="Anguilla"}, 30 | new NationCode{ChineseAbbr="南极洲",EnglishAbbr="ANTARCTICA",TwoCharCode="AQ",ThreeCharCode="ATA",DigitalCode="010",FullNameOfCHS="南极洲",FullNameOfENG="Antarctica"}, 31 | new NationCode{ChineseAbbr="安提瓜和巴布达",EnglishAbbr="ANTIGUA AND BARBUDA",TwoCharCode="AG",ThreeCharCode="ATG",DigitalCode="028",FullNameOfCHS="安提瓜和巴布达",FullNameOfENG="Antigua and Barbuda"}, 32 | new NationCode{ChineseAbbr="阿根廷",EnglishAbbr="ARGENTINA",TwoCharCode="AR",ThreeCharCode="ARG",DigitalCode="032",FullNameOfCHS="阿根廷共和国",FullNameOfENG="Republic of Argentina"}, 33 | new NationCode{ChineseAbbr="亚美尼亚",EnglishAbbr="ARMENIA",TwoCharCode="AM",ThreeCharCode="ARM",DigitalCode="051",FullNameOfCHS="亚美尼亚共和国",FullNameOfENG="Republic of Armenia"}, 34 | new NationCode{ChineseAbbr="阿鲁巴",EnglishAbbr="ARUBA",TwoCharCode="AW",ThreeCharCode="ABW",DigitalCode="533",FullNameOfCHS="阿鲁巴",FullNameOfENG="Aruba"}, 35 | new NationCode{ChineseAbbr="澳大利亚",EnglishAbbr="AUSTRALIA",TwoCharCode="AU",ThreeCharCode="AUS",DigitalCode="036",FullNameOfCHS="澳大利亚联邦",FullNameOfENG="Commonwealth ofAustralia"}, 36 | new NationCode{ChineseAbbr="奥地利",EnglishAbbr="AUSTRIA",TwoCharCode="AT",ThreeCharCode="AUT",DigitalCode="040",FullNameOfCHS="奥地利共和国",FullNameOfENG="Republic of Austria"}, 37 | new NationCode{ChineseAbbr="阿塞拜疆",EnglishAbbr="AZERBAIJAN",TwoCharCode="AZ",ThreeCharCode="AZE",DigitalCode="031",FullNameOfCHS="阿塞拜疆共和国",FullNameOfENG="Republic ofAzerbaijan"}, 38 | new NationCode{ChineseAbbr="巴哈马",EnglishAbbr="BAHAMAS",TwoCharCode="BS",ThreeCharCode="BHS",DigitalCode="044",FullNameOfCHS="巴哈马联邦",FullNameOfENG="Commonwealth of theBahamas"}, 39 | new NationCode{ChineseAbbr="巴林",EnglishAbbr="BAHRAIN",TwoCharCode="BH",ThreeCharCode="BHR",DigitalCode="048",FullNameOfCHS="巴林国",FullNameOfENG="State of Bahrain"}, 40 | new NationCode{ChineseAbbr="孟加拉国",EnglishAbbr="BANGLADESH",TwoCharCode="BD",ThreeCharCode="BGD",DigitalCode="050",FullNameOfCHS="孟加拉人民共和国",FullNameOfENG="People's Republicof Bangladesh"}, 41 | new NationCode{ChineseAbbr="巴巴多斯",EnglishAbbr="BARBADOS",TwoCharCode="BB",ThreeCharCode="BRB",DigitalCode="052",FullNameOfCHS="巴巴多斯",FullNameOfENG="Barbados"}, 42 | new NationCode{ChineseAbbr="白俄罗斯",EnglishAbbr="BELARUS",TwoCharCode="BY",ThreeCharCode="BLR",DigitalCode="112",FullNameOfCHS="白俄罗斯共和国",FullNameOfENG="Republic of Belarus"}, 43 | new NationCode{ChineseAbbr="比利时",EnglishAbbr="BELGIUM",TwoCharCode="BE",ThreeCharCode="BEL",DigitalCode="056",FullNameOfCHS="比利时王国",FullNameOfENG="Kingdom of belgium"}, 44 | new NationCode{ChineseAbbr="伯利兹",EnglishAbbr="BELIZE",TwoCharCode="BZ",ThreeCharCode="BLZ",DigitalCode="084",FullNameOfCHS="伯利兹",FullNameOfENG="Belize"}, 45 | new NationCode{ChineseAbbr="贝宁",EnglishAbbr="BENIN",TwoCharCode="BJ",ThreeCharCode="BEN",DigitalCode="204",FullNameOfCHS="贝宁共和国",FullNameOfENG="Republic of Benin"}, 46 | new NationCode{ChineseAbbr="百慕大",EnglishAbbr="BERMUDA",TwoCharCode="BM",ThreeCharCode="BMU",DigitalCode="060",FullNameOfCHS="百慕大群岛",FullNameOfENG="Bermuda Islands"}, 47 | new NationCode{ChineseAbbr="不丹",EnglishAbbr="BHUTAN",TwoCharCode="BT",ThreeCharCode="BTN",DigitalCode="064",FullNameOfCHS="不丹王国",FullNameOfENG="Kingdom of Bhutan"}, 48 | new NationCode{ChineseAbbr="玻利维亚",EnglishAbbr="BOLIVIA",TwoCharCode="BO",ThreeCharCode="BOL",DigitalCode="068",FullNameOfCHS="玻利维亚共和国",FullNameOfENG="Republic of Bolivia"}, 49 | new NationCode{ChineseAbbr="波黑",EnglishAbbr="BOSNIA ANDHERZEGOVINA",TwoCharCode="BA",ThreeCharCode="BIH",DigitalCode="070",FullNameOfCHS="波斯尼亚和黑塞哥维那",FullNameOfENG="Bosnia andHerzegovina"}, 50 | new NationCode{ChineseAbbr="博茨瓦纳",EnglishAbbr="BOTSWANA",TwoCharCode="BW",ThreeCharCode="BWA",DigitalCode="072",FullNameOfCHS="博茨瓦纳共和国",FullNameOfENG="Republic ofBotswana"}, 51 | new NationCode{ChineseAbbr="布维岛",EnglishAbbr="BOUVET ISLAND",TwoCharCode="BV",ThreeCharCode="BVT",DigitalCode="074",FullNameOfCHS="布维岛",FullNameOfENG="Bouvet Island"}, 52 | new NationCode{ChineseAbbr="巴西",EnglishAbbr="BRAZIL",TwoCharCode="BR",ThreeCharCode="BRA",DigitalCode="076",FullNameOfCHS="巴西联邦共和国",FullNameOfENG="Federative Republicof Brazil"}, 53 | new NationCode{ChineseAbbr="英属印度洋领土",EnglishAbbr="BRITISH INDIAN OCEANTER-RITORY",TwoCharCode="IO",ThreeCharCode="IOT",DigitalCode="086",FullNameOfCHS="英属印度洋领土",FullNameOfENG="British IndianOcean Territory"}, 54 | new NationCode{ChineseAbbr="文莱",EnglishAbbr="BRUNEI DARUSSALAM",TwoCharCode="BN",ThreeCharCode="BRN",DigitalCode="096",FullNameOfCHS="文莱达鲁萨兰国",FullNameOfENG="Brunei Darussalam"}, 55 | new NationCode{ChineseAbbr="保加利亚",EnglishAbbr="BULGARIA",TwoCharCode="BG",ThreeCharCode="BGR",DigitalCode="100",FullNameOfCHS="保加利亚共和国",FullNameOfENG="Republic ovBulgaria"}, 56 | new NationCode{ChineseAbbr="布基纳法索",EnglishAbbr="BURKINA FASO",TwoCharCode="BF",ThreeCharCode="BFA",DigitalCode="854",FullNameOfCHS="布基纳法索",FullNameOfENG="Burkina Faso"}, 57 | new NationCode{ChineseAbbr="布隆迪",EnglishAbbr="BURUNDI",TwoCharCode="BI",ThreeCharCode="BDI",DigitalCode="108",FullNameOfCHS="布隆迪共和国",FullNameOfENG="Republic of Burundi"}, 58 | new NationCode{ChineseAbbr="柬埔寨",EnglishAbbr="CAMBODIA",TwoCharCode="KH",ThreeCharCode="KHM",DigitalCode="116",FullNameOfCHS="柬埔寨王国",FullNameOfENG="Kingdom of Cambodia"}, 59 | new NationCode{ChineseAbbr="喀麦隆",EnglishAbbr="CAMEROON",TwoCharCode="CM",ThreeCharCode="CMR",DigitalCode="120",FullNameOfCHS="喀麦隆共和国",FullNameOfENG="Republic of Cameroon"}, 60 | new NationCode{ChineseAbbr="加拿大",EnglishAbbr="CANADA",TwoCharCode="CA",ThreeCharCode="CAN",DigitalCode="124",FullNameOfCHS="加拿大",FullNameOfENG="Canada"}, 61 | new NationCode{ChineseAbbr="佛得角",EnglishAbbr="CAPE VERDE",TwoCharCode="CV",ThreeCharCode="CPV",DigitalCode="132",FullNameOfCHS="佛得角共和国",FullNameOfENG="Republic of Cape Verde"}, 62 | new NationCode{ChineseAbbr="开曼群岛",EnglishAbbr="CAYMAN ISLANDS",TwoCharCode="KY",ThreeCharCode="CYM",DigitalCode="136",FullNameOfCHS="开曼群岛",FullNameOfENG="Cayman Islands"}, 63 | new NationCode{ChineseAbbr="中非",EnglishAbbr="CENTRAL AFRICA",TwoCharCode="CF",ThreeCharCode="CAF",DigitalCode="140",FullNameOfCHS="中非共和国",FullNameOfENG="Central African Republic"}, 64 | new NationCode{ChineseAbbr="乍得",EnglishAbbr="CHAD",TwoCharCode="TD",ThreeCharCode="TCD",DigitalCode="148",FullNameOfCHS="乍得共和国",FullNameOfENG="Republic of Chad"}, 65 | new NationCode{ChineseAbbr="智利",EnglishAbbr="CHILE",TwoCharCode="CL",ThreeCharCode="CHL",DigitalCode="152",FullNameOfCHS="智利共和国",FullNameOfENG="Republic of Chile"}, 66 | new NationCode{ChineseAbbr="中国",EnglishAbbr="CHINA",TwoCharCode="CN",ThreeCharCode="CHN",DigitalCode="156",FullNameOfCHS="中华人民共和国",FullNameOfENG="People's Republic of China"}, 67 | new NationCode{ChineseAbbr="香港",EnglishAbbr="HONG KONG",TwoCharCode="HK",ThreeCharCode="HKG",DigitalCode="344",FullNameOfCHS="香港",FullNameOfENG="Hong Kong"}, 68 | new NationCode{ChineseAbbr="澳门",EnglishAbbr="MACAU",TwoCharCode="MO",ThreeCharCode="MAC",DigitalCode="446",FullNameOfCHS="澳门",FullNameOfENG="Macau"}, 69 | new NationCode{ChineseAbbr="台湾",EnglishAbbr="TAIWAN, PROVINCE OF CHINA",TwoCharCode="TW",ThreeCharCode="TWN",DigitalCode="158",FullNameOfCHS="中国台湾",FullNameOfENG="Taiwan, Province of China"}, 70 | new NationCode{ChineseAbbr="圣诞岛",EnglishAbbr="CHRISTMAS ISLAND",TwoCharCode="CS",ThreeCharCode="CSR",DigitalCode="162",FullNameOfCHS="圣诞岛",FullNameOfENG="Christmas Island"}, 71 | new NationCode{ChineseAbbr="科科斯(基林)群岛",EnglishAbbr="COCOS(KEELING)ISLANDS",TwoCharCode="CC",ThreeCharCode="CCK",DigitalCode="166",FullNameOfCHS="科科斯(基林)群岛",FullNameOfENG="Cocos(Keeling)Islands"}, 72 | new NationCode{ChineseAbbr="哥伦比亚",EnglishAbbr="COLOMBIA",TwoCharCode="Co",ThreeCharCode="COL",DigitalCode="170",FullNameOfCHS="哥伦比亚共和国",FullNameOfENG="Republic ofColombia"}, 73 | new NationCode{ChineseAbbr="科摩罗",EnglishAbbr="COMOROS",TwoCharCode="KM",ThreeCharCode="COM",DigitalCode="174",FullNameOfCHS="科摩罗伊斯兰联邦共和国",FullNameOfENG="FederalIslamic Republic of the Co-moros"}, 74 | new NationCode{ChineseAbbr="刚果(布)",EnglishAbbr="CONGO",TwoCharCode="CG",ThreeCharCode="COG",DigitalCode="178",FullNameOfCHS="刚果共和国",FullNameOfENG="Republic of Congo"}, 75 | new NationCode{ChineseAbbr="刚果(金)",EnglishAbbr="CONGO, THE DEMOCRATICREPUBLIC OF THE",TwoCharCode="CD",ThreeCharCode="COD",DigitalCode="180",FullNameOfCHS="刚果民主共和国",FullNameOfENG="Democratic Republicof Congo"}, 76 | new NationCode{ChineseAbbr="库克群岛",EnglishAbbr="COOK ISLANDS",TwoCharCode="CK",ThreeCharCode="COK",DigitalCode="184",FullNameOfCHS="库克群岛",FullNameOfENG="Cook Islands"}, 77 | new NationCode{ChineseAbbr="哥斯达黎加",EnglishAbbr="COSTA RIC",TwoCharCode="AC",ThreeCharCode="RCR",DigitalCode="188",FullNameOfCHS="哥斯达黎加共和国",FullNameOfENG="Republic of CostaRica"}, 78 | new NationCode{ChineseAbbr="科特迪瓦",EnglishAbbr="COTE D'IVOIRE",TwoCharCode="CI",ThreeCharCode="CIV",DigitalCode="384",FullNameOfCHS="科特迪瓦共和国",FullNameOfENG="Republic of Coted'Ivire"}, 79 | new NationCode{ChineseAbbr="克罗地亚",EnglishAbbr="CROATIA",TwoCharCode="HR",ThreeCharCode="HRV",DigitalCode="191",FullNameOfCHS="克罗地亚共和国",FullNameOfENG="Republic of Croatia"}, 80 | new NationCode{ChineseAbbr="古巴",EnglishAbbr="CUBA",TwoCharCode="CU",ThreeCharCode="CUB",DigitalCode="192",FullNameOfCHS="古巴共和国",FullNameOfENG="Republic of Cuba"}, 81 | new NationCode{ChineseAbbr="塞浦路斯",EnglishAbbr="CYPRUS",TwoCharCode="CY",ThreeCharCode="CYP",DigitalCode="196",FullNameOfCHS="塞浦路斯共和国",FullNameOfENG="Republic of Cyprus"}, 82 | new NationCode{ChineseAbbr="捷克",EnglishAbbr="CZECH REPOUBLIC",TwoCharCode="CZ",ThreeCharCode="CZE",DigitalCode="203",FullNameOfCHS="捷克共和国",FullNameOfENG="Czech Republic"}, 83 | new NationCode{ChineseAbbr="丹麦",EnglishAbbr="DENMARK",TwoCharCode="DK",ThreeCharCode="DNK",DigitalCode="208",FullNameOfCHS="丹麦王国",FullNameOfENG="Kingdom of Denmark"}, 84 | new NationCode{ChineseAbbr="吉布提",EnglishAbbr="DJIBOUTI",TwoCharCode="DJ",ThreeCharCode="DJI",DigitalCode="262",FullNameOfCHS="吉布提共和国",FullNameOfENG="Republic of Djibouti"}, 85 | new NationCode{ChineseAbbr="多米尼克",EnglishAbbr="DOMINICA",TwoCharCode="DM",ThreeCharCode="DMA",DigitalCode="212",FullNameOfCHS="多米尼克联邦",FullNameOfENG="Commonwealth ofDominica"}, 86 | new NationCode{ChineseAbbr="多米尼加共和国",EnglishAbbr="DOMINICAN REPUBLIC",TwoCharCode="DO",ThreeCharCode="DOM",DigitalCode="214",FullNameOfCHS="多米尼加共和国",FullNameOfENG="Dominican Republic"}, 87 | new NationCode{ChineseAbbr="东帝汶",EnglishAbbr="EAST TIMOR",TwoCharCode="TP",ThreeCharCode="TMP",DigitalCode="626",FullNameOfCHS="东帝汶",FullNameOfENG="East Timor"}, 88 | new NationCode{ChineseAbbr="厄瓜多尔",EnglishAbbr="ECUADOR",TwoCharCode="EC",ThreeCharCode="ECU",DigitalCode="218",FullNameOfCHS="厄瓜多尔共和国",FullNameOfENG="Republic of Ecuador"}, 89 | new NationCode{ChineseAbbr="埃及",EnglishAbbr="EGYPT",TwoCharCode="EG",ThreeCharCode="EGY",DigitalCode="818",FullNameOfCHS="阿拉伯埃及共和国",FullNameOfENG="Arab Republic ofEgypt"}, 90 | new NationCode{ChineseAbbr="萨尔瓦多",EnglishAbbr="EL SALVADOR",TwoCharCode="SV",ThreeCharCode="SLV",DigitalCode="222",FullNameOfCHS="萨尔瓦多共和国",FullNameOfENG="Republic of ElSalvador"}, 91 | new NationCode{ChineseAbbr="赤道几内亚",EnglishAbbr="EQUATORIAL GUINEA",TwoCharCode="GQ",ThreeCharCode="GNQ",DigitalCode="226",FullNameOfCHS="赤道几内亚共和国",FullNameOfENG="Republic ofEquatorial Guinea"}, 92 | new NationCode{ChineseAbbr="厄立特里亚",EnglishAbbr="ERITREA",TwoCharCode="ER",ThreeCharCode="ERI",DigitalCode="232",FullNameOfCHS="厄立特里亚国",FullNameOfENG="State of Eritrea"}, 93 | new NationCode{ChineseAbbr="爱沙尼亚",EnglishAbbr="ESTONIA",TwoCharCode="EE",ThreeCharCode="EST",DigitalCode="233",FullNameOfCHS="爱沙尼亚共和国",FullNameOfENG="Republic of Estonia"}, 94 | new NationCode{ChineseAbbr="埃塞俄比亚",EnglishAbbr="ETHIOPIA",TwoCharCode="ET",ThreeCharCode="ETH",DigitalCode="231",FullNameOfCHS="埃塞俄比亚",FullNameOfENG="Ethiopia"}, 95 | new NationCode{ChineseAbbr="福克兰群岛(马尔维纳斯)",EnglishAbbr="FALKLAND ISLANDS(MALVINAS)",TwoCharCode="FK",ThreeCharCode="FLK",DigitalCode="238",FullNameOfCHS="福克兰群岛(马尔维纳斯)",FullNameOfENG="FalklandIslands(Malvinas)"}, 96 | new NationCode{ChineseAbbr="法罗群岛",EnglishAbbr="FAROE ISLANDS",TwoCharCode="FO",ThreeCharCode="FRO",DigitalCode="234",FullNameOfCHS="法罗群岛",FullNameOfENG="Faroe Islands"}, 97 | new NationCode{ChineseAbbr="斐济",EnglishAbbr="FIJI",TwoCharCode="FJ",ThreeCharCode="FJI",DigitalCode="242",FullNameOfCHS="斐济共和国",FullNameOfENG="Republic of Fiji"}, 98 | new NationCode{ChineseAbbr="芬兰",EnglishAbbr="FINLAND",TwoCharCode="FI",ThreeCharCode="FIN",DigitalCode="246",FullNameOfCHS="芬兰共和国",FullNameOfENG="Republic of Finland"}, 99 | new NationCode{ChineseAbbr="法国",EnglishAbbr="FRANCE",TwoCharCode="FR",ThreeCharCode="FRA",DigitalCode="250",FullNameOfCHS="法兰西共和国",FullNameOfENG="French Republic"}, 100 | new NationCode{ChineseAbbr="法属圭亚那",EnglishAbbr="FRENCH GUIANA",TwoCharCode="GF",ThreeCharCode="GUF",DigitalCode="254",FullNameOfCHS="法属圭亚那",FullNameOfENG="French Guiana"}, 101 | new NationCode{ChineseAbbr="法属波利尼西亚",EnglishAbbr="FRENCH POLYNESIA",TwoCharCode="PF",ThreeCharCode="PYF",DigitalCode="258",FullNameOfCHS="法属波利尼西亚",FullNameOfENG="French Polynesia"}, 102 | new NationCode{ChineseAbbr="法属南部领土",EnglishAbbr="FRENCH SOUTHERNTERRITO-RIES",TwoCharCode="TF",ThreeCharCode="ATF",DigitalCode="260",FullNameOfCHS="法属南部领土",FullNameOfENG="French SouthernTerritories"}, 103 | new NationCode{ChineseAbbr="加蓬",EnglishAbbr="GABON",TwoCharCode="GA",ThreeCharCode="GAB",DigitalCode="266",FullNameOfCHS="加蓬共和国",FullNameOfENG="Gabonese Republic"}, 104 | new NationCode{ChineseAbbr="冈比亚",EnglishAbbr="Gambia",TwoCharCode="GM",ThreeCharCode="GMB",DigitalCode="270",FullNameOfCHS="冈比亚共和国",FullNameOfENG="Republic of Gambia"}, 105 | new NationCode{ChineseAbbr="格鲁吉亚",EnglishAbbr="GEORGIA",TwoCharCode="GE",ThreeCharCode="GEO",DigitalCode="268",FullNameOfCHS="格鲁吉亚共和国",FullNameOfENG="Republic of Georgia"}, 106 | new NationCode{ChineseAbbr="德国",EnglishAbbr="GERMANY",TwoCharCode="DE",ThreeCharCode="DEU",DigitalCode="276",FullNameOfCHS="德意志联邦共和国",FullNameOfENG="Federal Republicof Germany"}, 107 | new NationCode{ChineseAbbr="加纳",EnglishAbbr="GHANA",TwoCharCode="GH",ThreeCharCode="GHA",DigitalCode="288",FullNameOfCHS="加纳共和国",FullNameOfENG="Republic of Ghana"}, 108 | new NationCode{ChineseAbbr="直布罗陀",EnglishAbbr="GIBRALTAR",TwoCharCode="GI",ThreeCharCode="GIB",DigitalCode="292",FullNameOfCHS="直布罗陀",FullNameOfENG="Gibraltar"}, 109 | new NationCode{ChineseAbbr="希腊",EnglishAbbr="GREECE",TwoCharCode="GR",ThreeCharCode="GRC",DigitalCode="300",FullNameOfCHS="希腊共和国",FullNameOfENG="Hellenic Republic"}, 110 | new NationCode{ChineseAbbr="格陵兰",EnglishAbbr="GREENLAND",TwoCharCode="GL",ThreeCharCode="GRL",DigitalCode="304",FullNameOfCHS="格陵兰",FullNameOfENG="Greenland"}, 111 | new NationCode{ChineseAbbr="格林纳达",EnglishAbbr="GRENADA",TwoCharCode="GD",ThreeCharCode="GRD",DigitalCode="308",FullNameOfCHS="格林纳达",FullNameOfENG="Grenada"}, 112 | new NationCode{ChineseAbbr="瓜德罗普",EnglishAbbr="GUADELOUPE",TwoCharCode="GP",ThreeCharCode="GLP",DigitalCode="312",FullNameOfCHS="瓜德罗普",FullNameOfENG="Guadeloupe"}, 113 | new NationCode{ChineseAbbr="关岛",EnglishAbbr="GUAM",TwoCharCode="GU",ThreeCharCode="GUM",DigitalCode="316",FullNameOfCHS="关岛",FullNameOfENG="Guam"}, 114 | new NationCode{ChineseAbbr="危地马拉",EnglishAbbr="GUATEMALA",TwoCharCode="GT",ThreeCharCode="GTM",DigitalCode="320",FullNameOfCHS="危地马拉共和国",FullNameOfENG="Republic ofGuatemala"}, 115 | new NationCode{ChineseAbbr="几内亚",EnglishAbbr="GUINEA",TwoCharCode="GN",ThreeCharCode="GIN",DigitalCode="324",FullNameOfCHS="几内亚共和国",FullNameOfENG="Republic of Guinea"}, 116 | new NationCode{ChineseAbbr="几内亚比绍",EnglishAbbr="GUINE-BISSAU",TwoCharCode="GW",ThreeCharCode="GNB",DigitalCode="624",FullNameOfCHS="几内亚比绍共和国",FullNameOfENG="Republic ofGuine-bissau"}, 117 | new NationCode{ChineseAbbr="圭亚那",EnglishAbbr="GUYANA",TwoCharCode="GY",ThreeCharCode="GUY",DigitalCode="328",FullNameOfCHS="圭亚那合作共和国",FullNameOfENG="CooperativeRepublic of Guyana"}, 118 | new NationCode{ChineseAbbr="海地",EnglishAbbr="HAITI",TwoCharCode="HT",ThreeCharCode="HTI",DigitalCode="332",FullNameOfCHS="海地共和国",FullNameOfENG="Republic of Haiti"}, 119 | new NationCode{ChineseAbbr="赫德岛和麦克唐纳岛",EnglishAbbr="HEARD ISLANDS AND MCDONALD ISLANDS",TwoCharCode="HM",ThreeCharCode="HMD",DigitalCode="334",FullNameOfCHS="赫德岛和麦克唐纳岛",FullNameOfENG="Heard islandsand Mc Donald Islands"}, 120 | new NationCode{ChineseAbbr="洪都拉斯",EnglishAbbr="HONDURAS",TwoCharCode="HN",ThreeCharCode="HND",DigitalCode="340",FullNameOfCHS="洪都拉斯共和国",FullNameOfENG="Republic ofhonduras"}, 121 | new NationCode{ChineseAbbr="匈牙利",EnglishAbbr="HUNGARY",TwoCharCode="HU",ThreeCharCode="HUN",DigitalCode="348",FullNameOfCHS="匈牙利共和国",FullNameOfENG="Republic of Hungary"}, 122 | new NationCode{ChineseAbbr="冰岛",EnglishAbbr="ICELAND",TwoCharCode="IS",ThreeCharCode="ISL",DigitalCode="352",FullNameOfCHS="冰岛共和国",FullNameOfENG="Republic of Iceland"}, 123 | new NationCode{ChineseAbbr="印度",EnglishAbbr="INDIA",TwoCharCode="IN",ThreeCharCode="IND",DigitalCode="356",FullNameOfCHS="印度共和国",FullNameOfENG="Republic of India"}, 124 | new NationCode{ChineseAbbr="印度尼西亚",EnglishAbbr="INDONESIA",TwoCharCode="ID",ThreeCharCode="IDN",DigitalCode="360",FullNameOfCHS="印度尼西亚共和国",FullNameOfENG="Republic ofIndonesia"}, 125 | new NationCode{ChineseAbbr="伊朗",EnglishAbbr="IRAN",TwoCharCode="IR",ThreeCharCode="IRN",DigitalCode="364",FullNameOfCHS="伊朗伊斯兰共和国",FullNameOfENG="Islamic Rupublicof Iran"}, 126 | new NationCode{ChineseAbbr="伊拉克",EnglishAbbr="IRAQ",TwoCharCode="IQ",ThreeCharCode="IRQ",DigitalCode="368",FullNameOfCHS="伊拉克共和国",FullNameOfENG="Republic of Iraq"}, 127 | new NationCode{ChineseAbbr="爱尔兰",EnglishAbbr="IRELAND",TwoCharCode="IE",ThreeCharCode="IRL",DigitalCode="372",FullNameOfCHS="爱尔兰",FullNameOfENG="Ireland"}, 128 | new NationCode{ChineseAbbr="以色列",EnglishAbbr="ISRAEL",TwoCharCode="IL",ThreeCharCode="ISR",DigitalCode="376",FullNameOfCHS="以色列国",FullNameOfENG="State of Israel"}, 129 | new NationCode{ChineseAbbr="意大利",EnglishAbbr="ITALY",TwoCharCode="IT",ThreeCharCode="ITA",DigitalCode="380",FullNameOfCHS="意大利共和国",FullNameOfENG="Republic of Italy"}, 130 | new NationCode{ChineseAbbr="牙买加",EnglishAbbr="JAMAICA",TwoCharCode="JM",ThreeCharCode="JAM",DigitalCode="388",FullNameOfCHS="牙买加",FullNameOfENG="Jamaica"}, 131 | new NationCode{ChineseAbbr="日本",EnglishAbbr="JAPAN",TwoCharCode="JP",ThreeCharCode="JPN",DigitalCode="392",FullNameOfCHS="日本国",FullNameOfENG="Japan"}, 132 | new NationCode{ChineseAbbr="约旦",EnglishAbbr="JORDAN",TwoCharCode="JO",ThreeCharCode="JOR",DigitalCode="400",FullNameOfCHS="约旦哈希姆王国",FullNameOfENG="Hashemite Kingdomof Jordan"}, 133 | new NationCode{ChineseAbbr="哈萨克斯坦",EnglishAbbr="KAZAKHSTAN",TwoCharCode="KZ",ThreeCharCode="KAZ",DigitalCode="398",FullNameOfCHS="哈萨克斯坦共和国",FullNameOfENG="Republic ofKazakhstan"}, 134 | new NationCode{ChineseAbbr="肯尼亚",EnglishAbbr="KENYA",TwoCharCode="KE",ThreeCharCode="KEN",DigitalCode="404",FullNameOfCHS="肯尼亚共和国",FullNameOfENG="Republic of Kenya"}, 135 | new NationCode{ChineseAbbr="基里巴斯",EnglishAbbr="KIRIBATI",TwoCharCode="KI",ThreeCharCode="KIR",DigitalCode="296",FullNameOfCHS="基里巴斯共和国",FullNameOfENG="Republic ofKiribati"}, 136 | new NationCode{ChineseAbbr="朝鲜",EnglishAbbr="KOREA,DEMOCRATICPEOPLE'S REPUBLIC OF",TwoCharCode="KP",ThreeCharCode="PRK",DigitalCode="408",FullNameOfCHS="朝鲜民主主义人民共和国",FullNameOfENG="DemocraticPeople's Republic of Ko-rea"}, 137 | new NationCode{ChineseAbbr="韩国",EnglishAbbr="KOREA,REPUBLIC OF",TwoCharCode="KR",ThreeCharCode="KOR",DigitalCode="410",FullNameOfCHS="大韩民国",FullNameOfENG="Republic of Korea"}, 138 | new NationCode{ChineseAbbr="科威特",EnglishAbbr="KUWAIT",TwoCharCode="KW",ThreeCharCode="KWT",DigitalCode="414",FullNameOfCHS="科威特国",FullNameOfENG="State of Kuwait"}, 139 | new NationCode{ChineseAbbr="吉尔吉斯斯坦",EnglishAbbr="KYRGYZSTAN",TwoCharCode="KG",ThreeCharCode="KGZ",DigitalCode="417",FullNameOfCHS="吉尔吉斯共和国",FullNameOfENG="Kyrgyz Republic"}, 140 | new NationCode{ChineseAbbr="老挝",EnglishAbbr="LAOS",TwoCharCode="LA",ThreeCharCode="LAO",DigitalCode="418",FullNameOfCHS="老挝人民民主共和国",FullNameOfENG="Lao People'sDemocratic Republic"}, 141 | new NationCode{ChineseAbbr="拉脱维亚",EnglishAbbr="LATVIA",TwoCharCode="LV",ThreeCharCode="LVA",DigitalCode="428",FullNameOfCHS="拉脱维亚共和国",FullNameOfENG="Republic of Latvia"}, 142 | new NationCode{ChineseAbbr="黎巴嫩",EnglishAbbr="LEBANON",TwoCharCode="LB",ThreeCharCode="LBN",DigitalCode="422",FullNameOfCHS="黎巴嫩共和国",FullNameOfENG="Republic of Lebanon"}, 143 | new NationCode{ChineseAbbr="莱索托",EnglishAbbr="LESOTHO",TwoCharCode="LS",ThreeCharCode="LSO",DigitalCode="426",FullNameOfCHS="莱索托王国",FullNameOfENG="Kingdom of Lesoto"}, 144 | new NationCode{ChineseAbbr="利比里亚",EnglishAbbr="LIBERIA",TwoCharCode="LR",ThreeCharCode="LBR",DigitalCode="430",FullNameOfCHS="利比里亚共和国",FullNameOfENG="Republic of Liberia"}, 145 | new NationCode{ChineseAbbr="利比亚",EnglishAbbr="LIBYA",TwoCharCode="LY",ThreeCharCode="LBY",DigitalCode="434",FullNameOfCHS="大阿拉伯利比亚人民社会主义民众国Great",FullNameOfENG="Socialist People's Libyan Arab jamahiriya"}, 146 | new NationCode{ChineseAbbr="列支敦士登",EnglishAbbr="LIECHTENSTEIN",TwoCharCode="LI",ThreeCharCode="LIE",DigitalCode="438",FullNameOfCHS="列支敦士登公国",FullNameOfENG="Principality ofLiechtenstein"}, 147 | new NationCode{ChineseAbbr="立陶宛",EnglishAbbr="LITHUANIA",TwoCharCode="LT",ThreeCharCode="LTU",DigitalCode="440",FullNameOfCHS="立陶宛共和国",FullNameOfENG="Republic of Lithuania"}, 148 | new NationCode{ChineseAbbr="卢森堡",EnglishAbbr="LUXEMBOURG",TwoCharCode="LU",ThreeCharCode="LUX",DigitalCode="442",FullNameOfCHS="卢森堡大公国",FullNameOfENG="Grand Duchy ofLuxembourg"}, 149 | new NationCode{ChineseAbbr="前南马其顿",EnglishAbbr="MACEDONIA, THE FORMERYUGOSLAV REPUBLIC OF",TwoCharCode="MK",ThreeCharCode="MKD",DigitalCode="807",FullNameOfCHS="前南斯拉夫马其顿共和国",FullNameOfENG="The FormerYugoslav Republic of Macedonia"}, 150 | new NationCode{ChineseAbbr="马达加斯加",EnglishAbbr="MADAGASCAR",TwoCharCode="MG",ThreeCharCode="MDG",DigitalCode="450",FullNameOfCHS="马达加斯加共和国",FullNameOfENG="Republic ofMadagascar"}, 151 | new NationCode{ChineseAbbr="马拉维",EnglishAbbr="MALAWI",TwoCharCode="MW",ThreeCharCode="MWI",DigitalCode="454",FullNameOfCHS="马拉维共和国",FullNameOfENG="Republic of Malawi"}, 152 | new NationCode{ChineseAbbr="马来西亚",EnglishAbbr="MALAYSIA",TwoCharCode="MY",ThreeCharCode="MYS",DigitalCode="458",FullNameOfCHS="马来西亚",FullNameOfENG="Malaysia"}, 153 | new NationCode{ChineseAbbr="马尔代夫",EnglishAbbr="MALDIVES",TwoCharCode="MV",ThreeCharCode="MDV",DigitalCode="462",FullNameOfCHS="马尔代夫共和国",FullNameOfENG="Republic ofmaldives"}, 154 | new NationCode{ChineseAbbr="马里",EnglishAbbr="MALI",TwoCharCode="ML",ThreeCharCode="MLI",DigitalCode="466",FullNameOfCHS="马里共和国",FullNameOfENG="Republic of Mali"}, 155 | new NationCode{ChineseAbbr="马耳他",EnglishAbbr="MALTA",TwoCharCode="MT",ThreeCharCode="MLT",DigitalCode="470",FullNameOfCHS="马耳他共和国",FullNameOfENG="Republic of Malta"}, 156 | new NationCode{ChineseAbbr="马绍尔群岛",EnglishAbbr="MARSHALL ISLANDS",TwoCharCode="MH",ThreeCharCode="MHL",DigitalCode="584",FullNameOfCHS="马绍尔群岛共和国",FullNameOfENG="Republic of themarshall Islands"}, 157 | new NationCode{ChineseAbbr="马提尼克",EnglishAbbr="MARTINIQUE",TwoCharCode="MQ",ThreeCharCode="MTQ",DigitalCode="474",FullNameOfCHS="马提尼克",FullNameOfENG="Martinique"}, 158 | new NationCode{ChineseAbbr="毛里塔尼亚",EnglishAbbr="MAURITANIA",TwoCharCode="MR",ThreeCharCode="MRT",DigitalCode="478",FullNameOfCHS="毛里求斯共和国",FullNameOfENG="Republic ofMauritius"}, 159 | new NationCode{ChineseAbbr="毛里求斯",EnglishAbbr="MAURITIUS",TwoCharCode="MU",ThreeCharCode="MUS",DigitalCode="480",FullNameOfCHS="毛里求斯共和国",FullNameOfENG="Republic ofMauritius"}, 160 | new NationCode{ChineseAbbr="马约特",EnglishAbbr="MAYOTTE",TwoCharCode="YT",ThreeCharCode="MYT",DigitalCode="175",FullNameOfCHS="马约特",FullNameOfENG="Mayotte"}, 161 | new NationCode{ChineseAbbr="墨西哥",EnglishAbbr="MEXICO",TwoCharCode="MX",ThreeCharCode="MEX",DigitalCode="484",FullNameOfCHS="墨西哥合众国",FullNameOfENG="United States ofMexico"}, 162 | new NationCode{ChineseAbbr="密克罗尼西亚联邦",EnglishAbbr="MICRONESIA, FEDERATEDSTATES OF",TwoCharCode="FM",ThreeCharCode="FSM",DigitalCode="583",FullNameOfCHS="密克罗尼西亚联邦",FullNameOfENG="Federated Statesof Micronesia"}, 163 | new NationCode{ChineseAbbr="摩尔多瓦",EnglishAbbr="MOLDOVA",TwoCharCode="MD",ThreeCharCode="MDA",DigitalCode="498",FullNameOfCHS="摩尔多瓦共和国",FullNameOfENG="Republic of Moldova"}, 164 | new NationCode{ChineseAbbr="摩纳哥",EnglishAbbr="MONACO",TwoCharCode="MC",ThreeCharCode="MCO",DigitalCode="492",FullNameOfCHS="摩纳哥公国",FullNameOfENG="Principality of Monaco"}, 165 | new NationCode{ChineseAbbr="蒙古",EnglishAbbr="MONGOLIA",TwoCharCode="MN",ThreeCharCode="MNG",DigitalCode="496",FullNameOfCHS="蒙古国",FullNameOfENG="Mongolia"}, 166 | new NationCode{ChineseAbbr="蒙特塞拉特",EnglishAbbr="MONTSERRAT",TwoCharCode="MS",ThreeCharCode="MSR",DigitalCode="500",FullNameOfCHS="蒙特塞拉特",FullNameOfENG="Montserrat"}, 167 | new NationCode{ChineseAbbr="摩洛哥",EnglishAbbr="MOROCCO",TwoCharCode="MA",ThreeCharCode="MAR",DigitalCode="504",FullNameOfCHS="摩洛哥王国",FullNameOfENG="Kingdom of Morocco"}, 168 | new NationCode{ChineseAbbr="莫桑比克",EnglishAbbr="MOZAMBIQUE",TwoCharCode="MZ",ThreeCharCode="MOZ",DigitalCode="508",FullNameOfCHS="莫桑比克共和国",FullNameOfENG="Republic ofMozambique"}, 169 | new NationCode{ChineseAbbr="缅甸",EnglishAbbr="MYANMAR",TwoCharCode="MM",ThreeCharCode="MMR",DigitalCode="104",FullNameOfCHS="缅甸联邦",FullNameOfENG="Union of Myanmar"}, 170 | new NationCode{ChineseAbbr="纳米比亚",EnglishAbbr="NAMIBIA",TwoCharCode="NA",ThreeCharCode="NAM",DigitalCode="516",FullNameOfCHS="纳米比亚共和国",FullNameOfENG="Republic of Namibia"}, 171 | new NationCode{ChineseAbbr="瑙鲁",EnglishAbbr="NAURU",TwoCharCode="NR",ThreeCharCode="NRU",DigitalCode="520",FullNameOfCHS="瑙鲁共和国",FullNameOfENG="Republic of Nauru"}, 172 | new NationCode{ChineseAbbr="尼泊尔",EnglishAbbr="NEPAL",TwoCharCode="NP",ThreeCharCode="NPL",DigitalCode="524",FullNameOfCHS="尼泊尔王国",FullNameOfENG="Kingdom of Nepal"}, 173 | new NationCode{ChineseAbbr="荷兰",EnglishAbbr="NETHERLANDS",TwoCharCode="NL",ThreeCharCode="NLD",DigitalCode="528",FullNameOfCHS="荷兰王国",FullNameOfENG="Kingdom of theNetherlands"}, 174 | new NationCode{ChineseAbbr="荷属安的列斯",EnglishAbbr="NETHERLANDS ANTILLES",TwoCharCode="AN",ThreeCharCode="ANT",DigitalCode="530",FullNameOfCHS="荷属安的列斯",FullNameOfENG="Netherlands Antilles"}, 175 | new NationCode{ChineseAbbr="新喀里多尼亚",EnglishAbbr="NEW CALEDONIA",TwoCharCode="NC",ThreeCharCode="NCL",DigitalCode="540",FullNameOfCHS="新喀里多尼亚",FullNameOfENG="New Caledonia"}, 176 | new NationCode{ChineseAbbr="新西兰",EnglishAbbr="NEW ZEALAND",TwoCharCode="NZ",ThreeCharCode="NZL",DigitalCode="554",FullNameOfCHS="新西兰",FullNameOfENG="New Zealand"}, 177 | new NationCode{ChineseAbbr="尼加拉瓜",EnglishAbbr="NICARAGUA",TwoCharCode="NI",ThreeCharCode="NIC",DigitalCode="558",FullNameOfCHS="尼加拉瓜共和国",FullNameOfENG="Republic ofNicaragua"}, 178 | new NationCode{ChineseAbbr="尼日尔",EnglishAbbr="NIGER",TwoCharCode="NE",ThreeCharCode="NER",DigitalCode="562",FullNameOfCHS="尼日尔共和国",FullNameOfENG="Republic of Niger"}, 179 | new NationCode{ChineseAbbr="尼日利亚",EnglishAbbr="NIGERIA",TwoCharCode="NG",ThreeCharCode="NGA",DigitalCode="566",FullNameOfCHS="尼日利亚联邦共和国",FullNameOfENG="FederalRepublic of Nigeria"}, 180 | new NationCode{ChineseAbbr="纽埃",EnglishAbbr="NIUE",TwoCharCode="NU",ThreeCharCode="NIU",DigitalCode="570",FullNameOfCHS="纽埃",FullNameOfENG="Niue"}, 181 | new NationCode{ChineseAbbr="诺福克岛",EnglishAbbr="NORFOLK ISLAND",TwoCharCode="NF",ThreeCharCode="NFK",DigitalCode="574",FullNameOfCHS="诺福克岛",FullNameOfENG="Norfolk Island"}, 182 | new NationCode{ChineseAbbr="北马里亚纳",EnglishAbbr="NORTHERN MARIANAS",TwoCharCode="MP",ThreeCharCode="MNP",DigitalCode="580",FullNameOfCHS="北马里亚纳自由联邦",FullNameOfENG="Commonwealth ofthe Northern Marianas"}, 183 | new NationCode{ChineseAbbr="挪威",EnglishAbbr="NORWAY",TwoCharCode="NO",ThreeCharCode="NOR",DigitalCode="578",FullNameOfCHS="挪威王国",FullNameOfENG="Kingdom of Norway"}, 184 | new NationCode{ChineseAbbr="阿曼",EnglishAbbr="OMAN",TwoCharCode="OM",ThreeCharCode="OMN",DigitalCode="512",FullNameOfCHS="阿曼苏丹国",FullNameOfENG="Sultanate of Oman"}, 185 | new NationCode{ChineseAbbr="巴基斯坦",EnglishAbbr="PAKISTAN",TwoCharCode="PK",ThreeCharCode="PAK",DigitalCode="586",FullNameOfCHS="巴基斯坦伊斯兰共和国",FullNameOfENG="IslamicRepublic of Pakistan"}, 186 | new NationCode{ChineseAbbr="帕劳",EnglishAbbr="PALAU",TwoCharCode="PW",ThreeCharCode="PLW",DigitalCode="585",FullNameOfCHS="帕劳共和国",FullNameOfENG="Republic of Palau"}, 187 | new NationCode{ChineseAbbr="巴勒斯坦",EnglishAbbr="PALESTINE",TwoCharCode="PS",ThreeCharCode="PST",DigitalCode="374",FullNameOfCHS="巴勒斯坦国",FullNameOfENG="State of Palestine"}, 188 | new NationCode{ChineseAbbr="巴拿马",EnglishAbbr="PANAMA",TwoCharCode="PA",ThreeCharCode="PAN",DigitalCode="591",FullNameOfCHS="巴拿马共和国",FullNameOfENG="Republic of Panama"}, 189 | new NationCode{ChineseAbbr="巴布亚新几内亚",EnglishAbbr="PAPUA NEW GUINEA",TwoCharCode="PG",ThreeCharCode="PNG",DigitalCode="598",FullNameOfCHS="巴布亚新几内亚独立国",FullNameOfENG="IndependentState of Papua New Guinea"}, 190 | new NationCode{ChineseAbbr="巴拉圭",EnglishAbbr="PARAGUAY",TwoCharCode="PY",ThreeCharCode="PRY",DigitalCode="600",FullNameOfCHS="巴拉圭共和国",FullNameOfENG="Republic of Paraguay"}, 191 | new NationCode{ChineseAbbr="秘鲁",EnglishAbbr="PERU",TwoCharCode="PE",ThreeCharCode="PER",DigitalCode="604",FullNameOfCHS="秘鲁共和国",FullNameOfENG="Republic of Peru"}, 192 | new NationCode{ChineseAbbr="菲律宾",EnglishAbbr="PHILIPPINES",TwoCharCode="PH",ThreeCharCode="PHL",DigitalCode="608",FullNameOfCHS="菲律宾共和国",FullNameOfENG="Republic of thePhilippines"}, 193 | new NationCode{ChineseAbbr="皮特凯恩群岛",EnglishAbbr="PITCAIRN ISLANDSGROUP",TwoCharCode="PN",ThreeCharCode="PCN",DigitalCode="612",FullNameOfCHS="皮竺凯恩群岛",FullNameOfENG="Pitcairn IslandsGroup"}, 194 | new NationCode{ChineseAbbr="波兰",EnglishAbbr="POLAND",TwoCharCode="PL",ThreeCharCode="POL",DigitalCode="616",FullNameOfCHS="波兰共和国",FullNameOfENG="Republic of Poland"}, 195 | new NationCode{ChineseAbbr="葡萄牙",EnglishAbbr="PORTUGAL",TwoCharCode="PT",ThreeCharCode="PRT",DigitalCode="620",FullNameOfCHS="葡萄牙共和国",FullNameOfENG="Pirtuguese Republic"}, 196 | new NationCode{ChineseAbbr="波多黎各",EnglishAbbr="PUERTO RICO",TwoCharCode="PR",ThreeCharCode="PRI",DigitalCode="630",FullNameOfCHS="波多黎各自由联邦",FullNameOfENG="Commonwealth ofPuerto Rico"}, 197 | new NationCode{ChineseAbbr="卡塔尔",EnglishAbbr="QATAR",TwoCharCode="QA",ThreeCharCode="QAT",DigitalCode="634",FullNameOfCHS="卡塔尔国",FullNameOfENG="State of Qatar"}, 198 | new NationCode{ChineseAbbr="留尼汪",EnglishAbbr="REUNION",TwoCharCode="RE",ThreeCharCode="REU",DigitalCode="638",FullNameOfCHS="留尼汪",FullNameOfENG="Reunion"}, 199 | new NationCode{ChineseAbbr="罗马尼亚",EnglishAbbr="ROMANIA",TwoCharCode="RO",ThreeCharCode="ROM",DigitalCode="642",FullNameOfCHS="罗马尼亚",FullNameOfENG="Romania"}, 200 | new NationCode{ChineseAbbr="俄罗斯联邦",EnglishAbbr="RUSSIAN FEDERATION",TwoCharCode="RU",ThreeCharCode="RUS",DigitalCode="643",FullNameOfCHS="俄罗斯联邦",FullNameOfENG="Russian Federation"}, 201 | new NationCode{ChineseAbbr="卢旺达",EnglishAbbr="RWANDA",TwoCharCode="RW",ThreeCharCode="RWA",DigitalCode="646",FullNameOfCHS="卢旺达共和国",FullNameOfENG="Republic of Rwanda"}, 202 | new NationCode{ChineseAbbr="圣赫勒拿",EnglishAbbr="SAINT HELENA",TwoCharCode="Sh",ThreeCharCode="SHN",DigitalCode="654",FullNameOfCHS="对赫勒拿",FullNameOfENG="Saint Helena"}, 203 | new NationCode{ChineseAbbr="圣基茨和尼维斯",EnglishAbbr="SAINT KITTS AND NEVIS",TwoCharCode="KN",ThreeCharCode="KNA",DigitalCode="659",FullNameOfCHS="圣革茨和尼维斯联邦",FullNameOfENG="Federation ofSaint Kitts and nevis"}, 204 | new NationCode{ChineseAbbr="圣卢西亚",EnglishAbbr="SAINT LUCIA",TwoCharCode="LC",ThreeCharCode="LCA",DigitalCode="662",FullNameOfCHS="圣卢西亚",FullNameOfENG="Saint Lucia"}, 205 | new NationCode{ChineseAbbr="圣皮埃尔和密克隆",EnglishAbbr="SAINT PIERRE ANDMIQUELON",TwoCharCode="PM",ThreeCharCode="SPM",DigitalCode="666",FullNameOfCHS="圣皮埃尔和密克隆",FullNameOfENG="Saint Pierre andMiquelon"}, 206 | new NationCode{ChineseAbbr="圣文森特和格林纳丁斯",EnglishAbbr="SAINT VINCENT AND THEGRENADINES",TwoCharCode="VC",ThreeCharCode="VCT",DigitalCode="670",FullNameOfCHS="圣文森特和格林纳丁斯",FullNameOfENG="Saint Vincentand the Grenadines"}, 207 | new NationCode{ChineseAbbr="萨摩亚",EnglishAbbr="SAMOA",TwoCharCode="WS",ThreeCharCode="WSM",DigitalCode="882",FullNameOfCHS="萨摩亚独立国",FullNameOfENG="Independent State ofSamoa"}, 208 | new NationCode{ChineseAbbr="圣马力诺",EnglishAbbr="SAN MARION",TwoCharCode="SM",ThreeCharCode="SMR",DigitalCode="674",FullNameOfCHS="圣马力诺共和国",FullNameOfENG="Republic of SanMarino"}, 209 | new NationCode{ChineseAbbr="圣多美和普林西 比",EnglishAbbr="SAO TOME AND PRINCIPE",TwoCharCode="St",ThreeCharCode="STp",DigitalCode="678",FullNameOfCHS="圣多美和普林西比民主共和国",FullNameOfENG="Democratic Republic of Sao Tomeand Principe"}, 210 | new NationCode{ChineseAbbr="沙特阿拉伯",EnglishAbbr="SAUDI ARABIA",TwoCharCode="SA",ThreeCharCode="SAU",DigitalCode="682",FullNameOfCHS="沙特阿拉伯王国",FullNameOfENG="Kingdom of SaudiArabia"}, 211 | new NationCode{ChineseAbbr="塞内加尔",EnglishAbbr="SENEGAL",TwoCharCode="SN",ThreeCharCode="SEN",DigitalCode="686",FullNameOfCHS="塞内加尔共和国",FullNameOfENG="Republic of Senegal"}, 212 | new NationCode{ChineseAbbr="塞舌尔",EnglishAbbr="SEYCHELLS",TwoCharCode="SC",ThreeCharCode="SYC",DigitalCode="690",FullNameOfCHS="塞舌尔共和国",FullNameOfENG="Republic ofSeychelles"}, 213 | new NationCode{ChineseAbbr="塞拉利昂",EnglishAbbr="SIERRA LEONE",TwoCharCode="SL",ThreeCharCode="SLE",DigitalCode="694",FullNameOfCHS="塞拉利昂共和国",FullNameOfENG="Republic of SierraLeone"}, 214 | new NationCode{ChineseAbbr="新加坡",EnglishAbbr="SINGAPORE",TwoCharCode="SG",ThreeCharCode="SGP",DigitalCode="702",FullNameOfCHS="新加坡共和国",FullNameOfENG="Republic of Singapore"}, 215 | new NationCode{ChineseAbbr="斯洛伐克",EnglishAbbr="SLOVAKIA",TwoCharCode="SK",ThreeCharCode="SVK",DigitalCode="703",FullNameOfCHS="斯洛伐克共和国",FullNameOfENG="Slovak Republic"}, 216 | new NationCode{ChineseAbbr="斯洛文尼亚",EnglishAbbr="SLOVENIA",TwoCharCode="SI",ThreeCharCode="SVN",DigitalCode="705",FullNameOfCHS="斯洛文尼亚共和国",FullNameOfENG="Republic ofSlovenia"}, 217 | new NationCode{ChineseAbbr="所罗门群岛",EnglishAbbr="SOLOMON ISLANDS",TwoCharCode="SB",ThreeCharCode="SLB",DigitalCode="090",FullNameOfCHS="年罗门群岛",FullNameOfENG="Solomon Islands"}, 218 | new NationCode{ChineseAbbr="索马里",EnglishAbbr="SOMALIA",TwoCharCode="SO",ThreeCharCode="SOM",DigitalCode="706",FullNameOfCHS="索马里共和国",FullNameOfENG="Somali Republic"}, 219 | new NationCode{ChineseAbbr="南非",EnglishAbbr="SOUTH AFRICA",TwoCharCode="ZA",ThreeCharCode="ZAF",DigitalCode="710",FullNameOfCHS="南非共和国",FullNameOfENG="Republic of SouthAfrica"}, 220 | new NationCode{ChineseAbbr="南乔治亚岛和南桑德韦奇岛",EnglishAbbr="SOUTH GEORGIA AND SOUTH SANDWICH ISLANDS",TwoCharCode="GS",ThreeCharCode="SGS",DigitalCode="239",FullNameOfCHS="南乔治亚岛和南桑德韦奇岛",FullNameOfENG="South Georgia and South Sandwich Islands"}, 221 | new NationCode{ChineseAbbr="西班牙",EnglishAbbr="SPAIN",TwoCharCode="ES",ThreeCharCode="ESP",DigitalCode="724",FullNameOfCHS="西班牙",FullNameOfENG="Spain"}, 222 | new NationCode{ChineseAbbr="斯里兰卡",EnglishAbbr="SRI LANKA",TwoCharCode="LK",ThreeCharCode="LKA",DigitalCode="144",FullNameOfCHS="斯里兰卡民主社会主义共和国",FullNameOfENG="Democratic Socialist Republic of Srilanka"}, 223 | new NationCode{ChineseAbbr="苏丹",EnglishAbbr="SUDAN",TwoCharCode="SD",ThreeCharCode="SDN",DigitalCode="736",FullNameOfCHS="苏丹共和国",FullNameOfENG="Republic of the Sudan"}, 224 | new NationCode{ChineseAbbr="苏里南",EnglishAbbr="SURINAME",TwoCharCode="SR",ThreeCharCode="SUR",DigitalCode="740",FullNameOfCHS="苏里南共和国",FullNameOfENG="Republic of Suriname"}, 225 | new NationCode{ChineseAbbr="斯瓦尔巴群岛",EnglishAbbr="SVALBARD AND JANMAYEN ISLANDS",TwoCharCode="SJ",ThreeCharCode="SJM",DigitalCode="744",FullNameOfCHS="斯瓦尔巴群岛",FullNameOfENG="Svalbard and Janmayen islands"}, 226 | new NationCode{ChineseAbbr="斯威士兰",EnglishAbbr="SWAZILAND",TwoCharCode="SZ",ThreeCharCode="SWZ",DigitalCode="748",FullNameOfCHS="斯威士兰王国",FullNameOfENG="Kingdom of Swaziland"}, 227 | new NationCode{ChineseAbbr="瑞典",EnglishAbbr="SWEDEN",TwoCharCode="SE",ThreeCharCode="SWE",DigitalCode="752",FullNameOfCHS="瑞典王国",FullNameOfENG="Kingdom of Sweden"}, 228 | new NationCode{ChineseAbbr="瑞士",EnglishAbbr="SWITZERLAND",TwoCharCode="CH",ThreeCharCode="CHE",DigitalCode="756",FullNameOfCHS="瑞士联邦",FullNameOfENG="Swiss Confederation"}, 229 | new NationCode{ChineseAbbr="叙利亚",EnglishAbbr="SYRIA",TwoCharCode="SY",ThreeCharCode="SYR",DigitalCode="760",FullNameOfCHS="阿拉伯叙利亚共和国",FullNameOfENG="Syrian ArabRepublic"}, 230 | new NationCode{ChineseAbbr="塔吉克斯坦",EnglishAbbr="TAJIKISTAN",TwoCharCode="TJ",ThreeCharCode="TJK",DigitalCode="762",FullNameOfCHS="塔吉克斯坦共和国",FullNameOfENG="Republic ofTajikistan"}, 231 | new NationCode{ChineseAbbr="坦桑尼亚",EnglishAbbr="TANZANIA",TwoCharCode="TZ",ThreeCharCode="TZA",DigitalCode="834",FullNameOfCHS="坦桑尼亚联合共和国",FullNameOfENG="United Republicof Tanzania"}, 232 | new NationCode{ChineseAbbr="泰国",EnglishAbbr="THAILAND",TwoCharCode="TH",ThreeCharCode="THA",DigitalCode="764",FullNameOfCHS="泰王国",FullNameOfENG="Kingdom of Thailand"}, 233 | new NationCode{ChineseAbbr="多哥",EnglishAbbr="TOGO",TwoCharCode="TG",ThreeCharCode="TGO",DigitalCode="768",FullNameOfCHS="多哥共和国",FullNameOfENG="Republic of Tago"}, 234 | new NationCode{ChineseAbbr="托克劳",EnglishAbbr="TOKELAU",TwoCharCode="TK",ThreeCharCode="TKL",DigitalCode="772",FullNameOfCHS="托克劳",FullNameOfENG="Tokelau"}, 235 | new NationCode{ChineseAbbr="汤加",EnglishAbbr="TONGA",TwoCharCode="TO",ThreeCharCode="TON",DigitalCode="776",FullNameOfCHS="汤加王国",FullNameOfENG="Kingdom of Tonga"}, 236 | new NationCode{ChineseAbbr="特立尼达和多巴哥",EnglishAbbr="TRINIDAD AND TOBAGO",TwoCharCode="TT",ThreeCharCode="TTO",DigitalCode="780",FullNameOfCHS="特立尼达和多巴哥共和国",FullNameOfENG="Republic ofTrinidad and Tobago"}, 237 | new NationCode{ChineseAbbr="突尼斯",EnglishAbbr="TUNISIA",TwoCharCode="TN",ThreeCharCode="TUN",DigitalCode="788",FullNameOfCHS="突尼斯共和国",FullNameOfENG="Republic of Tunisia"}, 238 | new NationCode{ChineseAbbr="土耳其",EnglishAbbr="TURKEY",TwoCharCode="TR",ThreeCharCode="TUR",DigitalCode="792",FullNameOfCHS="土耳其共和国",FullNameOfENG="Republic of Turkey"}, 239 | new NationCode{ChineseAbbr="土库曼斯坦",EnglishAbbr="TURKMENISTAN",TwoCharCode="TM",ThreeCharCode="TKM",DigitalCode="795",FullNameOfCHS="土库曼斯坦",FullNameOfENG="Turkmenistan"}, 240 | new NationCode{ChineseAbbr="特克斯科斯群岛",EnglishAbbr="TURKS AND CAICOS ISLANDS",TwoCharCode="TC",ThreeCharCode="TCA",DigitalCode="796",FullNameOfCHS="特克斯和凯科斯群岛",FullNameOfENG="Turks andCaicos Islands"}, 241 | new NationCode{ChineseAbbr="图瓦卢",EnglishAbbr="TUVALU",TwoCharCode="TV",ThreeCharCode="TUV",DigitalCode="798",FullNameOfCHS="图瓦卢",FullNameOfENG="Tuvalu"}, 242 | new NationCode{ChineseAbbr="乌干达",EnglishAbbr="UGANDA",TwoCharCode="UG",ThreeCharCode="UGA",DigitalCode="800",FullNameOfCHS="乌干达共和国",FullNameOfENG="Republic of Uganda"}, 243 | new NationCode{ChineseAbbr="乌克兰",EnglishAbbr="UKRAINE",TwoCharCode="UA",ThreeCharCode="UKR",DigitalCode="804",FullNameOfCHS="乌克兰",FullNameOfENG="Ukraine"}, 244 | new NationCode{ChineseAbbr="阿联酋",EnglishAbbr="UNITED ARAB EMIRATES",TwoCharCode="AE",ThreeCharCode="ARE",DigitalCode="784",FullNameOfCHS="拉伯联合酋长国",FullNameOfENG="United ArabEmirates"}, 245 | new NationCode{ChineseAbbr="英国",EnglishAbbr="UNITED KINGDOM",TwoCharCode="GB",ThreeCharCode="GBR",DigitalCode="826",FullNameOfCHS="大不列颠及北爱尔兰联合王国",FullNameOfENG="UnitedKingdom of Great Britain and Northern ireland"}, 246 | new NationCode{ChineseAbbr="美国",EnglishAbbr="UNITED STATES",TwoCharCode="US",ThreeCharCode="USA",DigitalCode="840",FullNameOfCHS="美利坚合众国",FullNameOfENG="United States ofAmerica"}, 247 | new NationCode{ChineseAbbr="美国本土外小岛屿",EnglishAbbr="UNITED STATES MINOR OUTLYING ISLANDS",TwoCharCode="UM",ThreeCharCode="UMI",DigitalCode="581",FullNameOfCHS="美国本土外小岛屿",FullNameOfENG="United StatesMinor Outlying Islands"}, 248 | new NationCode{ChineseAbbr="乌拉圭",EnglishAbbr="URUGUAY",TwoCharCode="UY",ThreeCharCode="URY",DigitalCode="858",FullNameOfCHS="乌拉圭东岸共和国",FullNameOfENG="Oriental Republicof Uruguay"}, 249 | new NationCode{ChineseAbbr="乌兹别克斯坦",EnglishAbbr="UZBEKISTAN",TwoCharCode="UZ",ThreeCharCode="UZB",DigitalCode="860",FullNameOfCHS="乌兹别克斯坦共和国",FullNameOfENG="Republic ofUzbekistan"}, 250 | new NationCode{ChineseAbbr="瓦努阿图",EnglishAbbr="VANUATU",TwoCharCode="VU",ThreeCharCode="VUT",DigitalCode="548",FullNameOfCHS="瓦努阿图共和国",FullNameOfENG="Republic of Vanuatu"}, 251 | new NationCode{ChineseAbbr="梵蒂冈",EnglishAbbr="VATICAN",TwoCharCode="VA",ThreeCharCode="VAT",DigitalCode="336",FullNameOfCHS="梵蒂冈城国",FullNameOfENG="Vatican City State"}, 252 | new NationCode{ChineseAbbr="委内瑞拉",EnglishAbbr="VENEZUELA",TwoCharCode="VE",ThreeCharCode="VEN",DigitalCode="862",FullNameOfCHS="委内瑞拉共和国",FullNameOfENG="Republic ofVenezuela"}, 253 | new NationCode{ChineseAbbr="越南",EnglishAbbr="VIET NAM",TwoCharCode="VN",ThreeCharCode="VNM",DigitalCode="704",FullNameOfCHS="越南社会主席共和国",FullNameOfENG="SocialistRepublic of Viet Nam"}, 254 | new NationCode{ChineseAbbr="英属维尔京群岛",EnglishAbbr="VIRGIN ISLANDS,BRITISH",TwoCharCode="VG",ThreeCharCode="VGB",DigitalCode="092",FullNameOfCHS="英属维尔京群岛",FullNameOfENG="British VirginIslands"}, 255 | new NationCode{ChineseAbbr="美属维尔京群岛",EnglishAbbr="VIRGIN ISLANDS,U.S.",TwoCharCode="VI",ThreeCharCode="VIR",DigitalCode="850",FullNameOfCHS="美属维尔京群岛",FullNameOfENG="Virgin Islands ofthe United States"}, 256 | new NationCode{ChineseAbbr="瓦利斯和富图纳",EnglishAbbr="WALLIS AND FUTUNA",TwoCharCode="WF",ThreeCharCode="WLF",DigitalCode="876",FullNameOfCHS="瓦利斯和富图纳群岛",FullNameOfENG="Wallis andFutuna"}, 257 | new NationCode{ChineseAbbr="西撒哈拉",EnglishAbbr="WESTERN SAHARA",TwoCharCode="EH",ThreeCharCode="ESH",DigitalCode="732",FullNameOfCHS="西撒哈拉",FullNameOfENG="Western Sahara"}, 258 | new NationCode{ChineseAbbr="也门",EnglishAbbr="YEMEN",TwoCharCode="YE",ThreeCharCode="YEM",DigitalCode="887",FullNameOfCHS="也门共和国",FullNameOfENG="Republic of Yemen"}, 259 | new NationCode{ChineseAbbr="南斯拉夫",EnglishAbbr="YUGOSLAVIA",TwoCharCode="YU",ThreeCharCode="YUG",DigitalCode="891",FullNameOfCHS="南斯拉夫联盟共和国",FullNameOfENG="FederalRepublic of Yugoslavia"}, 260 | new NationCode{ChineseAbbr="赞比亚",EnglishAbbr="ZAMBIA",TwoCharCode="ZM",ThreeCharCode="ZMB",DigitalCode="894",FullNameOfCHS="赞比亚共和国",FullNameOfENG="Republic of Zambia"}, 261 | new NationCode{ChineseAbbr="津巴布韦",EnglishAbbr="ZIMBABWE",TwoCharCode="ZW",ThreeCharCode="ZWE",DigitalCode="716",FullNameOfCHS="津巴布韦共和国",FullNameOfENG="Republic ofZimbabwe"}, 262 | #endregion 263 | }; 264 | }); 265 | } 266 | } 267 | /// 268 | /// 中文简称 269 | /// 270 | public string ChineseAbbr { get; set; } 271 | /// 272 | /// 英文简称 273 | /// 274 | public string EnglishAbbr { get; set; } 275 | /// 276 | /// 二字符代码 277 | /// 278 | public string TwoCharCode { get; set; } 279 | /// 280 | /// 三字符代码 281 | /// 282 | public string ThreeCharCode { get; set; } 283 | /// 284 | /// 数字代码 285 | /// 286 | public string DigitalCode { get; set; } 287 | /// 288 | /// 中文全称 289 | /// 290 | public string FullNameOfCHS { get; set; } 291 | /// 292 | /// 英文全称 293 | /// 294 | public string FullNameOfENG { get; set; } 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/ISO/ISO7064_1983.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Utils.ISO 7 | { 8 | /// 9 | /// ISO7064_1983 10 | /// 11 | public static class ISO7064_1983 12 | { 13 | /// 14 | /// 根据ISO7064:1983.MOD 11,2标准获取余 15 | /// 16 | /// 要MOD的原始数组 17 | /// 加权因子 18 | /// 取模值 19 | /// 20 | public static int MOD_11_2(int[] source, int[] weightingFactors, int mod) 21 | { 22 | if (source == null || weightingFactors == null || source.Length != weightingFactors.Length) 23 | { 24 | throw new ArgumentException("输入参数不符合ISO7064 MOD 11,2规范"); 25 | } 26 | int sum = source.Select((num, idx) => num * weightingFactors[idx]).Sum(); 27 | return sum % mod; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/RandomHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators.Utils 7 | { 8 | /// 9 | /// 随机数生成帮助类 10 | /// 11 | public static class RandomHelper 12 | { 13 | /// 14 | /// 按种子生成随机数 15 | /// 16 | /// 17 | /// 18 | public static int GetRandomNumber(this int seed) 19 | { 20 | return Math.Abs(Guid.NewGuid().GetHashCode()) % seed; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/ReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace NumberValidators.Utils 8 | { 9 | /// 10 | /// 反射接口帮助类 11 | /// 12 | internal static class ReflectionHelper 13 | { 14 | private static readonly ConcurrentDictionary concurrentDictionary 15 | = new ConcurrentDictionary(); 16 | /// 17 | /// 根据接口类型以及类名来获取对应的实现 18 | /// 19 | /// 20 | /// 21 | /// 22 | internal static object FindByInterface(Type interfaceType, string className) 23 | { 24 | string key = string.Format("{0}:{1}", interfaceType.FullName, className); 25 | return concurrentDictionary.GetOrAdd(key, _ => 26 | { 27 | try 28 | { 29 | var type = AppDomain.CurrentDomain.GetAssemblies() 30 | .SelectMany(a => a.GetTypes().Where(t => t.Name.Equals(className) && t.GetInterface(interfaceType.Name) != null)) 31 | .FirstOrDefault(); 32 | return type?.Assembly.CreateInstance(type.FullName); 33 | } 34 | catch { return null; } 35 | }); 36 | } 37 | /// 38 | /// 获取指定类名的接口实现 39 | /// 40 | /// 41 | /// 42 | /// 43 | internal static T FindByInterface(string className) 44 | { 45 | return (T)FindByInterface(typeof(T), className); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/RegexPatterns.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace NumberValidators.Utils 6 | { 7 | /// 8 | /// 证件相关的正则表达式 9 | /// 10 | public static class RegexPatterns 11 | { 12 | /* 13 | * 港澳台通行证参考地址 http://www.xm-l-tax.gov.cn/xmdscms/fgk/news/20040.html 14 | */ 15 | 16 | /// 17 | /// 台湾居民来往大陆通行证(包含旧规则) 18 | /// 因为2006年5月开始,内地公安机关签发的5年台胞通行证取消了小括号(即原办证机构代码),而目前已经是2017,所以已不存在有效期内有小括号的通行证,故正则不考虑小括号 19 | /// 理论上应该也不再存在有效期内的10位台湾居民来往大陆通行证,但这里还做支持 20 | /// 21 | public const string TaiwanPassFull = @"^\d{8}(\d{2})?$"; 22 | /// 23 | /// 台湾居民来往大陆通行证(最新规则) 24 | /// 25 | public const string TaiwanPass = @"^\d{8}$"; 26 | /// 27 | /// 港澳居民来往内地通行证(包含旧规则) 28 | /// 29 | public const string HongKongAndMacaoPassFull = @"^[HM]\d{8}(\d{2})?$"; 30 | /// 31 | /// 港澳居民来往内地通行证(最新规则) 32 | /// 33 | public const string HongKongAndMacaoPass = @"^[HM]\d{8}$"; 34 | /// 35 | /// 港澳台通行证(包含旧规则) 36 | /// 37 | public const string HMTPassFull = @"^[HM]?\d{8}(\d{2})?$"; 38 | /// 39 | /// 港澳台通行证(最新规则) 40 | /// 41 | public const string HMTPass = @"^[HM]?\d{8}$"; 42 | /// 43 | /// 15位一代大陆居民身份证 44 | /// 45 | public const string FirstIdentityCard = @"^[1-8]\d{14}$"; 46 | /// 47 | /// 18位二代大陆居民身份证 48 | /// 49 | public const string SecondIdentityCard = @"^[1-8]\d{16}[0-9xX]$"; 50 | /// 51 | /// 大陆居民身份证 52 | /// 53 | public const string IdentityCard = @"^[1-8]\d{14}(\d{2}[0-9xX])?$"; 54 | /// 55 | /// 增值税普通、专用发票代码、货物运输业增值税专用发票 56 | /// 57 | public const string VATCode10 = @"^\d{8}[2-9][0-4]$"; 58 | /// 59 | /// 增值税电子普通、普通(卷票)、区块链电子发票 60 | /// 61 | public const string VATCode12 = @"^[01]\d{11}$"; 62 | /// 63 | /// 工商注册码 64 | /// 65 | public const string BusinessRegistrationNo = @"^\d{15}$"; 66 | /// 67 | /// 法人和其他组织统一社会信用代码 68 | /// 69 | public const string UnifiedSocialCreditCode = @"^[0-9A-HJ-NP-RTUW-Y]{2}\d{6}[0-9A-HJ-NP-RTUW-Y]{10}$"; 70 | /// 71 | /// 中国大陆护照,注意不包含特区护照(港澳特区护照) 72 | /// 因私电子护照新字段2017.04启动 http://www.ailvxing.com/info-103-24211-0.html 第二位使用字母,排除IO,暂时这里符合规定只允许第二位输入字母,估计未来后7位也可能采用同样规则 73 | /// 按知乎上的回复,2017年8月底已经是EB开头的护照,大致估算是4个月用掉一个字段,24个字段大致能用96个月,也就是8年,即至少到2025年应该还不会采用第三个字段英文字母 74 | /// 因公电子护照规则 http://dfoca.hainan.gov.cn/wsqbzw/gzdt/201205/t20120507_671172.html 2012开始启用因公电子护照,对应有效期,目前应该不再存在非电子因公护照了,但这里匹配上还做支持 75 | /// 76 | public const string ChinesePassport = @"^(?:G\d{8}|[DSP]E?\d{7}|E[0-9A-HJ-NP-Z]\d{7})$"; 77 | /// 78 | /// 通用护照标准,按国际民航组织9303约定,最大不能超过9位 79 | /// 80 | public const string GeneralPassport = @"^[0-9A-Za-z]{5,9}$"; 81 | 82 | /* 83 | * 纳税人识别号 http://blog.sina.com.cn/s/blog_5fb8de860102vvpd.html 84 | * 组织结构是15位,法人是20位,补全依据 http://www.doc88.com/p-3985541443573.html 85 | * 三证合一后的社会统一验证代码也是纳税人识别号 86 | * 自然人是18位,对于一代身份证不清楚是否和法人一样补全3位0 87 | * 其它证件,也就是15位的无法获取校验位计算规则 88 | */ 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/NumberValidators/Utils/ValidatorHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NumberValidators.Utils 4 | { 5 | /// 6 | /// 验证帮助类 7 | /// 8 | public static class ValidatorHelper 9 | { 10 | /// 11 | /// 获取对应长度号码验证类实现 12 | /// 13 | /// 验证结果类 14 | /// 验证接口 15 | /// 待验证的号码 16 | /// 已有的验证结果类 17 | /// 要查找的className的格式,注意占位符{0}为number.Length,如不按照此规则,则不要传入占位符 18 | /// 未能找到实现时的错误描述,注意占位符{0}为number.Length,如不按照此规则,则不要传入占位符 19 | /// 验证接口实现类 20 | /// 要查找的接口类型,传null代表默认搜索typeof(IValidator) 21 | /// 22 | public static bool ValidImplement(string number, TResult result, string classNameFormat, string errorMsgFormat, out T validator, Type interfaceType = null) 23 | where TResult : ValidationResult, new() 24 | where T : class, IValidator 25 | { 26 | validator = ReflectionHelper.FindByInterface(interfaceType ?? typeof(IValidator<>), string.Format(classNameFormat, number.Length)) as T; 27 | var valid = validator != null; 28 | if (!valid) 29 | { 30 | result.AddErrorMessage(errorMsgFormat, number.Length); 31 | } 32 | return valid; 33 | } 34 | /// 35 | /// 验证号码长度是否符合希望验证的长度 36 | /// 37 | /// 验证结果类 38 | /// 待验证的号码 39 | /// 需验证的长度,不验证则传null 40 | /// 长度不符时的错误描述,注意占位符{0}为number.Length,如不按照此规则,则不要传入占位符 41 | /// 验证结果类 42 | /// 43 | public static bool ValidLength(string number, int? validLength, string errorMsgFormat, TResult result) 44 | where TResult : ValidationResult, new() 45 | { 46 | bool valid = !validLength.HasValue || number.Length == validLength; 47 | if (!valid) 48 | { 49 | result.AddErrorMessage(errorMsgFormat, validLength); 50 | } 51 | return valid; 52 | } 53 | /// 54 | /// 验证号码是否为空 55 | /// 56 | /// 泛型 57 | /// 要验证的号码 58 | /// 验证结果类 59 | /// 为空时的错误提示信息 60 | /// 61 | public static bool ValidEmpty(string number, out TResult result, string errorMsg) 62 | where TResult : ValidationResult, new() 63 | { 64 | result = new TResult() 65 | { 66 | Number = number 67 | }; 68 | if (string.IsNullOrWhiteSpace(number)) 69 | { 70 | result.AddErrorMessage(errorMsg); 71 | } 72 | return result.IsValid; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/NumberValidators/ValidationResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace NumberValidators 7 | { 8 | /// 9 | /// 号码验证结果类 10 | /// 11 | public class ValidationResult 12 | { 13 | /// 14 | /// 验证结果是否通过 15 | /// 16 | public bool IsValid { get; internal set; } = true; 17 | /// 18 | /// 如果验证不通过,这里包含验证失败的原因 19 | /// 20 | public IList Errors { get; internal set; } = new List(); 21 | /// 22 | /// 当前验证的号码 23 | /// 24 | public string Number { get; internal set; } 25 | 26 | /// 27 | /// 添加错误信息 28 | /// 29 | /// 30 | /// 31 | internal void AddErrorMessage(string errorMsg, params object[] parameters) 32 | { 33 | if (parameters != null && parameters.Length > 0) 34 | { 35 | errorMsg = string.Format(errorMsg, parameters); 36 | } 37 | this.Errors.Add(errorMsg); 38 | this.IsValid = false; 39 | } 40 | } 41 | } 42 | --------------------------------------------------------------------------------