C#中的IBAN验证,Excel自动化加载项,Word智能标记






3.36/5 (10投票s)
在C#中实现IBAN验证算法,并将其用作Excel UDF和Word智能标记。
引言
在一个项目中,我需要一个IBAN(国际银行账号)验证器。我搜索了校验和计算的方法,并在IBAN维基百科条目中找到了它。我还从UN CEFACT TBG5网站上找到了一个非常好的JavaScript示例。由于我需要在C#中使用该算法,因此我根据这些网站提供的信息开发了一个C#版本。使用相同的代码,我还通过VSTO创建了一个自定义的Excel工作表函数作为自动化加载项和一个Word的智能标记。
背景
IBAN在其维基百科条目中描述如下
校验和是一种基本的ISO 7064 mod 97-10计算,其中余数必须等于1。要验证校验和
- 根据国家/地区检查IBAN的总长度是否正确。如果不正确,则IBAN无效。
- 将前四个字符移到字符串的末尾。
- 将字符串中的每个字母替换为两个数字,从而扩展字符串,其中A=10,B=11,...,Z=35。
- 将字符串解释为十进制整数,并计算该数字除以97的余数。
只有当余数为1时,IBAN号才有效。
Using the Code
在C#中应用此算法时,大致如下(我承认这可能不是最佳算法)
internal static class Iban
{
public static StatusData CheckIban(string iban, bool cleanText)
{
if (cleanText) // remove empty space & convert all uppercase
iban = Regex.Replace(iban, @"\s", "").ToUpper();
if (Regex.IsMatch(iban, @"\W"))
return new StatusData(false, "The IBAN contains illegal characters.");
if (!Regex.IsMatch(iban, @"^\D\D\d\d.+"))
return new StatusData(false, "The structure of IBAN is wrong.");
if (Regex.IsMatch(iban, @"^\D\D00.+|^\D\D01.+|^\D\D99.+"))
return new StatusData(false, "The check digits of IBAN are wrong.");
string countryCode = iban.Substring(0, 2);
IbanData currentIbanData = (from id in IBANList()
where id.CountryCode == countryCode
select id).FirstOrDefault();
if (currentIbanData == null)
return new StatusData(false,
string.Format("IBAN for country {0} currently is not avaliable.",
countryCode));
if (iban.Length != currentIbanData.Lenght)
return new StatusData(false,
string.Format("The IBAN of {0} needs to be {1} characters long.",
countryCode, currentIbanData.Lenght));
if (!Regex.IsMatch(iban.Remove(0, 4), currentIbanData.RegexStructure))
return new StatusData(false,
"The country specific structure of IBAN is wrong.");
string modifiedIban = iban.ToUpper().Substring(4) + iban.Substring(0, 4);
modifiedIban = Regex.Replace(modifiedIban, @"\D",
m => ((int)m.Value[0] - 55).ToString());
int remainer = 0;
while (modifiedIban.Length >= 7)
{
remainer = int.Parse(remainer + modifiedIban.Substring(0, 7)) % 97;
modifiedIban = modifiedIban.Substring(7);
}
remainer = int.Parse(remainer + modifiedIban) % 97;
if (remainer != 1)
return new StatusData(false, "The IBAN is incorrect.");
return new StatusData(true, "The IBAN seems to be correct.");
}
public static List<IbanData> IBANList()
{
List<IbanData> newList = new List<IbanData>();
newList.Add(new IbanData("AD", 24,
@"\d{8}[a-zA-Z0-9]{12}", false,
"AD1200012030200359100100"));
//.... other countries
newList.Add(new IbanData("TR", 26,
@"\d{5}[a-zA-Z0-9]{17}", false,
"TR330006100519786457841326"));
return newList;
}
}
UN CEFACT TBG5网站上提供的JavaScript在一个数组中包含了维基百科列出的所有可用国家特定数据。我决定将这些数据存储为内部List<IbanData>
。由于我想向我的IbanChecker
返回比true
-false
更多的信息,所以我还创建了一个状态数据类。
public class IbanData
{
public string CountryCode;
public int Lenght;
public string RegexStructure;
public bool IsEU924;
public string Sample;
}
public class StatusData
{
public bool IsValid;
public string Message;
}
Microsoft Excel的IBAN自动化加载项
我认为如果可以在Excel工作表中找到这个检查器会非常有帮助。我可以使用VBScript的正则表达式支持(Set regex = CreateObject("VBScript.RegExp"
)轻松创建一个VBA解决方案。但是,我想创建一个可以部署到组织用户计算机的解决方案。Microsoft建议开发的客户端Excel UDF的方法是XLL,您必须将其开发为一种特殊的DLL,使用C API。如果您想为Excel Services(用于SharePoint)开发,已经有一个库可供您用于托管代码(Microsoft.Office.Excel.Server.Udf)。
我决定开发一个Excel自动化加载项,其中我可以使用我的托管代码作为COM互操作程序集。
public interface IExcelFunctions
{
string CheckIban(string iban);
bool RegexIsMatch(string cellValue, string regexPattern);
string RegexMatchValue(string cellValue, string regexPattern);
string[,] RegexAllMatchValues(string cellValue, string regexPattern);
}
[ComVisible(true), Guid("3....")]
[ComDefaultInterface(typeof(IExcelFunctions))]
public class ExcelFunctions : IExcelFunctions
{
public ExcelFunctions()
{
}
public string CheckIban(string iban)
{
StatusData status = Iban.CheckIban(iban, false);
return status.Message;
}
#region COM Registration
[ComRegisterFunctionAttribute]
public static void RegisterFunction(Type type)
{
Registry.ClassesRoot.CreateSubKey(GetSubKeyName(type, "Programmable"));
RegistryKey key = Registry.ClassesRoot.OpenSubKey(
GetSubKeyName(type, "InprocServer32"), true);
key.SetValue("", System.Environment.SystemDirectory +
@"\mscoree.dll", RegistryValueKind.String);
}
[ComUnregisterFunctionAttribute]
public static void UnregisterFunction(Type type)
{
Registry.ClassesRoot.DeleteSubKey(GetSubKeyName(type,
"Programmable"), false);
}
private static string GetSubKeyName(Type type, string subKeyName)
{
System.Text.StringBuilder s = new System.Text.StringBuilder();
s.Append(@"CLSID\{");
s.Append(type.GUID.ToString().ToUpper());
s.Append(@"}\");
s.Append(subKeyName);
return s.ToString();
}
#endregion
}
将此托管DLL注册为COM互操作程序集后,您需要将其在Excel中激活。为此:Office按钮 -> Excel选项 -> 加载项 -> “管理:Excel加载项” 转到... -> 自动化... -> ExcelExtension.ExcelFunctions -> 确定 -> 确定。
然后,您就可以从“插入函数”对话框中使用它了。
有关开发自动化加载项的更多详细信息,您可以从Eric Carter和Gabhan Berry的两个博客文章开始。要将托管代码DLL注册为COM互操作程序集,您可以从Regasm.exe和这篇文章(以及这个技巧)开始。如果您计划在公司范围内进行部署,您应该已经知道这一点。请参见下文获取正则表达式示例。
Microsoft Word的IBAN智能标记
公司中的大部分通信都是用Word编写的。如果字母中输入的IBAN代码是正确的还是不正确的,有一个智能标记会通知您会很好。对于开发智能标记,最简单的方法是使用Office的Visual Studio工具。
public class IbanTag : SmartTag
{
private ResourceManager rm;
public IbanTag()
: base("http://iban.saltug.net/iban#IbanTag", "IBAN")
{
Microsoft.Office.Tools.Word.Action ibanAction =
new Microsoft.Office.Tools.Word.Action("Validate");
this.Expressions.Add(new System.Text.RegularExpressions.Regex(
@"(?'iban'\D\D\d\d\S+)"));
ibanAction.BeforeCaptionShow +=
new BeforeCaptionShowEventHandler(ibanAction_BeforeCaptionShow);
this.Actions = new Microsoft.Office.Tools.Word.Action[] { ibanAction };
rm = new ResourceManager("IbanSmartTag.string",
System.Reflection.Assembly.GetExecutingAssembly());
}
private void ibanAction_BeforeCaptionShow(object sender, ActionEventArgs e)
{
string iban = e.Properties.get_Read("iban");
CultureInfo ci = new CultureInfo(e.Range.LanguageID.GetHashCode());
IbanStatusData status = IbanChecker.CheckIban(iban, true, ci);
((Microsoft.Office.Tools.Word.Action)sender).Caption = status.IsValid
? rm.GetString("IbanIsvalid", ci)
: rm.GetString("IbanIsNotValid", ci) +
"-> " + status.Message;
}
}
这是Word中的一个示例。
要为Word开发智能标记,您可以阅读本教程。
在IBAN自动化加载项中使用正则表达式工作表函数
在处理Excel时,特别是当它包含我需要操作的文本和数字时,我总是觉得缺少可以在工作表函数中使用的正则表达式。在开发上述Excel加载项之后,我添加了对最常用的正则表达式函数的附加功能:IsMatch
、Match().Value
和all Match().Value
。
#region Regex Functions
public bool RegexIsMatch(string cellValue, string regexPattern)
{
return Regex.IsMatch(cellValue, regexPattern);
}
public string RegexMatchValue(string cellValue, string regexPattern)
{
return Regex.Match(cellValue, regexPattern).Value;
}
public string[,] RegexAllMatchValues(string cellValue, string regexPattern)
{
List resultList = new List();
Match matchResult = Regex.Match(cellValue, regexPattern);
while (matchResult.Success)
{
resultList.Add(matchResult.Value);
matchResult = matchResult.NextMatch();
}
string[,] resultValues = new string[resultList.Count, 1];
for (int i = 0; i < resultList.Count; i++)
resultValues[i, 0] = resultList[i];
return resultValues;
}
#endregion
示例结果
正如您所见,RegexAllMatchValues
函数返回一个字符串数组。为了看到所有结果,您需要对可以容纳结果的单元格应用数组公式。您可以在RegExLib.com找到许多正则表达式示例。