mirror of
https://gitee.com/akwkevin/aistudio.-wpf.-diagram
synced 2026-04-22 09:26:35 +08:00
260 lines
7.8 KiB
C#
260 lines
7.8 KiB
C#
/*
|
|
* Copyright 2014 ZXing authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
using System;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace ZXing.Client.Result
|
|
{
|
|
/// <summary>
|
|
/// Detects a result that is likely a vehicle identification number.
|
|
/// @author Sean Owen
|
|
/// </summary>
|
|
public class VINResultParser : ResultParser
|
|
{
|
|
#if SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE || UNITY || NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2
|
|
private static readonly Regex IOQ = new Regex("[IOQ]");
|
|
private static readonly Regex AZ09 = new Regex(@"\A(?:" + "[A-Z0-9]{17}" + @")\z");
|
|
#else
|
|
private static readonly Regex IOQ = new Regex("[IOQ]", RegexOptions.Compiled);
|
|
private static readonly Regex AZ09 = new Regex(@"\A(?:" + "[A-Z0-9]{17}" + @")\z", RegexOptions.Compiled);
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// attempt to parse the raw result to the specific type
|
|
/// </summary>
|
|
/// <param name="result"></param>
|
|
/// <returns></returns>
|
|
public override ParsedResult parse(ZXing.Result result)
|
|
{
|
|
try
|
|
{
|
|
if (result.BarcodeFormat != BarcodeFormat.CODE_39)
|
|
{
|
|
return null;
|
|
}
|
|
var rawText = result.Text;
|
|
rawText = IOQ.Replace(rawText, "").Trim();
|
|
var az09Match = AZ09.Match(rawText);
|
|
if (!az09Match.Success)
|
|
{
|
|
return null;
|
|
}
|
|
if (!checkChecksum(rawText))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var wmi = rawText.Substring(0, 3);
|
|
return new VINParsedResult(rawText,
|
|
wmi,
|
|
rawText.Substring(3, 6),
|
|
rawText.Substring(9, 8),
|
|
countryCode(wmi),
|
|
rawText.Substring(3, 5),
|
|
modelYear(rawText[9]),
|
|
rawText[10],
|
|
rawText.Substring(11));
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static bool checkChecksum(String vin)
|
|
{
|
|
var sum = 0;
|
|
for (var i = 0; i < vin.Length; i++)
|
|
{
|
|
sum += vinPositionWeight(i + 1) * vinCharValue(vin[i]);
|
|
}
|
|
var currentCheckChar = vin[8];
|
|
var expectedCheckChar = checkChar(sum % 11);
|
|
return currentCheckChar == expectedCheckChar;
|
|
}
|
|
|
|
private static int vinCharValue(char c)
|
|
{
|
|
if (c >= 'A' && c <= 'I')
|
|
{
|
|
return (c - 'A') + 1;
|
|
}
|
|
if (c >= 'J' && c <= 'R')
|
|
{
|
|
return (c - 'J') + 1;
|
|
}
|
|
if (c >= 'S' && c <= 'Z')
|
|
{
|
|
return (c - 'S') + 2;
|
|
}
|
|
if (c >= '0' && c <= '9')
|
|
{
|
|
return c - '0';
|
|
}
|
|
throw new ArgumentException(c.ToString());
|
|
}
|
|
|
|
private static int vinPositionWeight(int position)
|
|
{
|
|
if (position >= 1 && position <= 7)
|
|
{
|
|
return 9 - position;
|
|
}
|
|
if (position == 8)
|
|
{
|
|
return 10;
|
|
}
|
|
if (position == 9)
|
|
{
|
|
return 0;
|
|
}
|
|
if (position >= 10 && position <= 17)
|
|
{
|
|
return 19 - position;
|
|
}
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
private static char checkChar(int remainder)
|
|
{
|
|
if (remainder < 10)
|
|
{
|
|
return (char)('0' + remainder);
|
|
}
|
|
if (remainder == 10)
|
|
{
|
|
return 'X';
|
|
}
|
|
throw new ArgumentException();
|
|
}
|
|
|
|
private static int modelYear(char c)
|
|
{
|
|
if (c >= 'E' && c <= 'H')
|
|
{
|
|
return (c - 'E') + 1984;
|
|
}
|
|
if (c >= 'J' && c <= 'N')
|
|
{
|
|
return (c - 'J') + 1988;
|
|
}
|
|
if (c == 'P')
|
|
{
|
|
return 1993;
|
|
}
|
|
if (c >= 'R' && c <= 'T')
|
|
{
|
|
return (c - 'R') + 1994;
|
|
}
|
|
if (c >= 'V' && c <= 'Y')
|
|
{
|
|
return (c - 'V') + 1997;
|
|
}
|
|
if (c >= '1' && c <= '9')
|
|
{
|
|
return (c - '1') + 2001;
|
|
}
|
|
if (c >= 'A' && c <= 'D')
|
|
{
|
|
return (c - 'A') + 2010;
|
|
}
|
|
throw new ArgumentException(c.ToString());
|
|
}
|
|
|
|
private static String countryCode(String wmi)
|
|
{
|
|
char c1 = wmi[0];
|
|
char c2 = wmi[1];
|
|
switch (c1)
|
|
{
|
|
case '1':
|
|
case '4':
|
|
case '5':
|
|
return "US";
|
|
case '2':
|
|
return "CA";
|
|
case '3':
|
|
if (c2 >= 'A' && c2 <= 'W')
|
|
{
|
|
return "MX";
|
|
}
|
|
break;
|
|
case '9':
|
|
if ((c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9'))
|
|
{
|
|
return "BR";
|
|
}
|
|
break;
|
|
case 'J':
|
|
if (c2 >= 'A' && c2 <= 'T')
|
|
{
|
|
return "JP";
|
|
}
|
|
break;
|
|
case 'K':
|
|
if (c2 >= 'L' && c2 <= 'R')
|
|
{
|
|
return "KO";
|
|
}
|
|
break;
|
|
case 'L':
|
|
return "CN";
|
|
case 'M':
|
|
if (c2 >= 'A' && c2 <= 'E')
|
|
{
|
|
return "IN";
|
|
}
|
|
break;
|
|
case 'S':
|
|
if (c2 >= 'A' && c2 <= 'M')
|
|
{
|
|
return "UK";
|
|
}
|
|
if (c2 >= 'N' && c2 <= 'T')
|
|
{
|
|
return "DE";
|
|
}
|
|
break;
|
|
case 'V':
|
|
if (c2 >= 'F' && c2 <= 'R')
|
|
{
|
|
return "FR";
|
|
}
|
|
if (c2 >= 'S' && c2 <= 'W')
|
|
{
|
|
return "ES";
|
|
}
|
|
break;
|
|
case 'W':
|
|
return "DE";
|
|
case 'X':
|
|
if (c2 == '0' || (c2 >= '3' && c2 <= '9'))
|
|
{
|
|
return "RU";
|
|
}
|
|
break;
|
|
case 'Z':
|
|
if (c2 >= 'A' && c2 <= 'R')
|
|
{
|
|
return "IT";
|
|
}
|
|
break;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
} |