Files
aistudio-wpf-diagram/zxing.core/zxing.core/client/result/VINResultParser.cs
2021-07-23 09:42:22 +08:00

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;
}
}
}