站点图标 久久日记本

[身份证号码生成]细说哈希表和字典

目录

一个小小的问题引发的联想,仅仅是为了学习一下哈希表和字典,没想到一下子写了这么多,姑且做个总结吧。实在想不出该用什么标题,随便聊聊。

1.添加编号、省份和编号、地区 对照信息

这个需要用到键值对,想想List,只能用到List<string>,倒是没见过使用List<string ,string>刚开始想到了哈希表,然后又想到二维数组和字典,斟酌再三,于是选中字典。理由如下

二维数组在长度和添加更多的省市对照信息时候需要考虑不少,搞不定多了就晕的要超出长度了;

HashTable在遍历时会大乱顺序;

Dictionay和HashTable比较字典速度更快。(在某个博客看到的)

首先,我们来添加省份对照信息,这方面,百度文库可以出来:

初始化:

// 使用字典初始化
Dictionary<string, string> dtpro = new Dictionary<string, string>();//省份
Dictionary<string, string> dtplace = new Dictionary<string, string>();//城市

添加编号、省份对照表:

/// <summary>
/// 添加编号、省份对照信息
/// xxx.add("xx");让我想起了List<string>中的add
/// </summary>
public void adddtpro()
{
    #region 添加省份信息
  dtpro.Add("11", "北京市");
    dtpro.Add("12", "天津市");
    dtpro.Add("13", "河北省");
    dtpro.Add("14", "山西省");
    dtpro.Add("15", "内蒙古自治区");
    dtpro.Add("21", "辽宁省");
    dtpro.Add("22", "吉林省");
    dtpro.Add("23", "黑龙江省");
    dtpro.Add("31", "上海市");
    dtpro.Add("32", "江苏省");
    dtpro.Add("33", "浙江省");
    dtpro.Add("34", "安徽省");
    dtpro.Add("35", "福建省");
    dtpro.Add("36", "江西省");
    dtpro.Add("37", "山东省");
    dtpro.Add("41", "河南省");
    dtpro.Add("42", "湖北省");
    dtpro.Add("43", "湖南省");
    dtpro.Add("44", "广东省");
    dtpro.Add("45", "广西壮族自治区");
    dtpro.Add("46", "海南省");
    dtpro.Add("50", "重庆市");
    dtpro.Add("51", "四川省");
    dtpro.Add("52", "贵州省");
    dtpro.Add("53", "云南省");
    dtpro.Add("54", "西藏自治区");
    dtpro.Add("61", "陕西省");
    dtpro.Add("62", "甘肃省");
    dtpro.Add("63", "青海省");
    dtpro.Add("64", "宁夏回族自治区");
    dtpro.Add("65", "新疆维吾尔自治区");
    dtpro.Add("71", "台湾省");
    dtpro.Add("81", "香港特别行政区");
    dtpro.Add("82", "澳门特别行政区");
    #endregion
}

添加编号、城市对照表:(改的手麻,卡,还好有正则替换的记事本)

/// <summary>
/// 添加编号、城市对照信息
/// </summary>
public void adddtplace()
{
    //大约3400多条,问一下博客园的同志,是不是码长了?怎么一直插入失败呢
}

这样,就把省份和城市的信息初始化了,需要时调用就行,先别急,这是我们的准备工作。

2.检查身份证号码前两位(省份)

既然把省份和城市信息搞定,那么我们是不是得准备一个附加功能,提供对身份信息的查询呢,这样,就意味着要检查前两位号码;因为信息不多,姑且用数组尝尝味道把,

/// <summary>
/// 检查前2个
/// </summary>
/// <param name="str">前2个数字</param>
/// <returns>返回省份</returns>
public string checkpro(string str)
{
    string[,] proarray = new string[,] { { "北京市", "11" }, { "天津市", "12" }, { "河北省", "13" }, { "山西省", "14" }, { "内蒙古自治区", "15" }, { "辽宁省", "21" }, { "吉林省", "22" }, { "黑龙江省", "23" }, { "上海市", "31" }, { "江苏省", "32" }, { "浙江省", "33" }, { "安徽省", "34" }, { "福建省", "35" }, { "江西省", "36" }, { "山东省", "37" }, { "河南省", "41" }, { "湖北省", "42" }, { "湖南省", "43" }, { "广东省", "44" }, { "广西壮族自治区", "45" }, { "海南省", "46" }, { "重庆市", "50" }, { "四川省", "51" }, { "贵州省", "52" }, { "云南省", "53" }, { "西藏自治区", "54" }, { "陕西省", "61" }, { "甘肃省", "62" }, { "青海省", "63" }, { "宁夏回族自治区", "64" }, { "新疆维吾尔自治区", "65" }, { "台湾省", "71" }, { "香港特别行政区", "81" }, { "澳门特别行政区", "82" } };

    string prostr = "";

    for (int i = 0; i < proarray.Length / 2; i++)
    {
        if (proarray[i, 1] == str)
        {
            prostr = proarray[i, 0];

            break;
        }
    }
    return prostr;
}
3.判断城市信息

这里,我们提供一个对身份证编号前6位的查询方法,这样就可以查询到具体城市。

/// <summary>
/// 判断城市信息
/// </summary>
/// <param name="str">前6位</param>
/// <returns>返回所在位置,没有则返回空</returns>
public string checkplace(string str)
{
    adddtplace();//得先初始化信息将其添加到字典
    //ContainsKey:这是字典中的一个方法,有点类似HashTable,我们在 1 中增加了dtplace并在上一行初始化了,现在信息已经存入字典。
    //这里的ContainsKey是查看key里面,键值对,即键中 是否包含str
    if (dtplace.ContainsKey(str))
        return dtplace[str].ToString();//返回城市名称
    else
        return "";//没有则返回空
}
4.检查校验码

理解校验码可以查看某百科,这是复制下来的话:

①、将前面的身份证号码17位数分别乘以不同的系数。第i位对应的数为[2^(18-i)]mod11(这个是什么意思?没理解)。从第一位到第十七位的系数分别为:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 ;

②、将这17位数字和系数相乘的结果相加;

③、用加出来和除以11,看余数是多少?;

④、余数只可能有0 1 2 3 4 5 6 7 8 9 10这11个数字。其分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2;

⑤、通过上面得知如果余数是2,就会在身份证的第18位数字上出现罗马数字的Ⅹ。如果余数是10,身份证的最后一位号码就是2;

例如:某男性的身份证号码是34052419800101001X。我们要看看这个身份证是不是合法的身份证。
首先:我们得出,前17位的乘积和是189
然后:用189除以11得出的结果是17 + 2/11,也就是说余数是2。
最后:通过对应规则就可以知道余数2对应的数字是x。所以,这是一个合格的身份证号码。

好了,我们用程序生成,代码如下:

/// <summary>
/// 检查校验码
/// </summary>
/// <param name="str">输入前17位</param>
/// <returns>返回校验码</returns>
public string checkcode(string str)
{
    int sumno = 0;
    sumno += strToint(str[0].ToString()) * 7;
    sumno += strToint(str[1].ToString()) * 9;
    sumno += strToint(str[2].ToString()) * 10;
    sumno += strToint(str[3].ToString()) * 5;
    sumno += strToint(str[4].ToString()) * 8;
    sumno += strToint(str[5].ToString()) * 4;
    sumno += strToint(str[6].ToString()) * 2;
    sumno += strToint(str[7].ToString()) * 1;
    sumno += strToint(str[8].ToString()) * 6;
    sumno += strToint(str[9].ToString()) * 3;

    sumno += strToint(str[10].ToString()) * 7;
    sumno += strToint(str[11].ToString()) * 9;
    sumno += strToint(str[12].ToString()) * 10;
    sumno += strToint(str[13].ToString()) * 5;
    sumno += strToint(str[14].ToString()) * 8;
    sumno += strToint(str[15].ToString()) * 4;
    sumno += strToint(str[16].ToString()) * 2;

    int result = sumno % 11;
    string checkcode = "-1";
    switch (result)
    {
        case 0:
            checkcode = "1";
            break;
        case 1:
            checkcode = "0";
            break;
        case 2:
            checkcode = "X";
            break;
        case 3:
            checkcode = "9";
            break;
        case 4:
            checkcode = "8";
            break;
        case 5:
            checkcode = "7";
            break;
        case 6:
            checkcode = "6";
            break;
        case 7:
            checkcode = "5";
            break;
        case 8:
            checkcode = "4";
            break;
        case 9:
            checkcode = "3";
            break;
        case 10:
            checkcode = "2";
            break;
        default:
            checkcode = "-1";
            break;
    }
    return checkcode;
}
5.判断闰年

在让用户选择日期的时候,是不是得考虑到下来列表的情况呢?

有点类似级联表,即上述的省份和城市对照表,就是例子。当然年月日也是这样,考虑闰年中的2月29天和28天情况。当年份整除以4并且不能整除以100或者整除以400的情况下才是闰年。

用代码判断吧:

/// <summary>
/// 判断是否闰年
/// </summary>
/// <param name="year">年份</param>
/// <returns>返回bool值</returns>
public bool cheakYear(int year)
{
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
    {
        return true;
    }
    else
    {
        return false;
    }
}
6.检查年月日是否正确

涉及到闰年中的2月。闰年2月29天,非闰年2月28天。

/// <summary>
/// 检查年月日是否正确
/// </summary>
/// <param name="str">输入前17位</param>
/// <returns>返回错误提示,没有错误则返回空字符串</returns>
public string checkdate(string str)
{
    int checkyear = strToint(str[6].ToString() + str[7].ToString() + str[8].ToString() + str[9].ToString());
    int checkmonth = strToint(str[10].ToString() + str[11].ToString());
    int checkday = strToint(str[12].ToString() + str[13].ToString());

    int year = strToint(DateTime.Now.Year.ToString());//当前年份
    int month = strToint(DateTime.Now.Month.ToString());//当前月份
    int day = strToint(DateTime.Now.Day.ToString());//当前几号

    if (checkyear > year || checkyear + 100 < year)
        return "输入年份尚未生效或已经过期!";
    else
    {
        if (checkmonth < 1 || checkmonth > 12)
            return "月份有误!";
        else
        {

            //获取输入月份下该月份天数
            //判断是否闰年
            if (checkday < 0)
                return "日期有误";
            else
            {
                if (checkmonth == 1 || checkmonth == 3 || checkmonth == 5 || checkmonth == 7 || checkmonth == 9 || checkmonth == 11 || checkmonth == 12)
                {
                    if (checkday > 31)
                        return "日期有误!";
                }
                if (checkmonth == 2)
                {
                    if (cheakYear(checkyear) && checkday > 29)
                    {
                        return "2月日期有误!";
                    }
                    if (!cheakYear(checkyear) && checkday > 28)
                    {
                        return "2月日期有误!";

                    }
                }
                if ((checkmonth == 4 || checkmonth == 6 || checkmonth == 8 || checkmonth == 10) && checkday > 30)
                {
                    return "日期有误!";
                }
            }
            return "";
        }
    }
}
7.初始化省份,城市信息(级联表)

我们的省份信息添加到字典了,城市信息也添加了,这会儿,是不是做一下将其添加到下拉列表前的准备呢。(PS:我真没想到我为什么还要定义一个ArrayList然后而不是ContainsKey判断直接传值,难道是为了绑定数据源方便么?因为写这个玩意过了去了三个月,忘了,有没有人帮我解释一下。)

ArrayList alpro = new ArrayList();
ArrayList alplace = new ArrayList();
/// <summary>
/// 初始化省份信息(添加到alpro中)
/// </summary>
/// <returns>返回省份<编号,省份>的arraylist</returns>
public ArrayList matchpro()
{
    adddtpro();
    adddtplace();
    foreach (var item in dtpro)
    {
        alpro.Add(new DictionaryEntry(item.Key, item.Value));
    }
    return alpro;
}
/// <summary>
/// 根据省份初始化城市信息(添加到alplace上)
/// </summary>
/// <param name="strpro">省份代号</param>
/// <returns>返回城市<编号,城市>的arraylist</returns>
public ArrayList matchplace(string strpro)
{
    alplace.Clear();//清空数据
    foreach (var item in dtplace)
    {
        string itemkey = item.Key.ToString();
        if ((itemkey[0].ToString() + itemkey[1].ToString().ToString() == strpro))
        {
            //0000为省份代号
            if ((itemkey[0].ToString() + itemkey[1].ToString() + itemkey[2].ToString() + itemkey[3].ToString().ToString() != "0000"))
            {
                alplace.Add(new DictionaryEntry(item.Key, item.Value));
                //如果用hashtable用foreach遍历再add之后会发现顺序被打乱
            }
        }
    }
    return alplace;
}
8.UI,真正的开始

以上方法我都将其保存到新建的一个类中,命名为ClassCheck.cs,仅仅作为准备工作,

下面,才算是真正的开始,看图如下:

其中命名

省份:cbpro;

城市:cbplace

年、月、日:cbyear 、cbmonth、cbday

性别:cbsex

生成结果的listbox:lbresult

功能区:Get:btnGet;copy:btnCopy;Remove:btnRemove;Check:btnCheck;Output:btnout

9.初始化省、城市、年月日、性别

初始化之前,我们先把我们刚才积累的一些方法用到这里,

实例化类,刚才我们不是把一些准备的方法放到了cs里面了么,现在先准备好:

ClassCheck clcheck = new ClassCheck();
int choseplace = 0;//当没选择城市时初始化为0,后面要用

先上简单点的年月日、性别 初始化

①.添加年份:

//添加年份
private void beginyear()
{
    //1950-当前年份
    int year = DateTime.Now.Year;
    for (int i = 1950; i <= year; i++)
    {
        cbyear.Items.Add(i);
    }
}

②.添加月份:

//添加月份
private void beginmonth()
{
    //1-当前月
    //两种情况,当前年以前,1-12个月;算了,麻烦,又得判断,就用12个月吧,这样是不是还没出生的都有了
    //选1-12
    //int month = DateTime.Now.Month;
    for (int i = 1; i <= 12; i++)
    {
        cbmonth.Items.Add(i);
    }
}

③.添加当月天数:

//添加当月天数
private void beginday()
{
    //分为闰年 的2月判断
    //这里是不是就用到了类中的方法了
    bool byear = clcheck.cheakYear(Convert.ToInt32(cbyear.Text.Trim()));
    switch (cbmonth.Text)
    {
        case "4":
        case "6":
        case "8":
        case "10":
            for (int i = 1; i <= 30; i++)
            {
                cbday.Items.Add(i);
            }
            break;
        case "2":
            if (byear)
            {
                for (int i = 1; i <= 29; i++)
                {
                    cbday.Items.Add(i);
                }
            }
            else
            {
                for (int i = 1; i <= 28; i++)
                {
                    cbday.Items.Add(i);
                }

            }
            break;
        default:
            for (int i = 1; i <= 31; i++)
            {
                cbday.Items.Add(i);
            }
            break;

    }
}

④.添加性别:

//添加性别
private void beginsex() 
{
    cbsex.Items.Add("男");
    cbsex.Items.Add("女");
}

⑤.两级联动

根据省份(编号)匹配城市(编号)(前两个数字匹配),绑定到下拉列表中

/// <summary>
/// 两级联动,根据省份编号匹配城市(前两个数字)
/// </summary>
/// <param name="strpro"></param>
private void begindata(string strpro)
{
    ArrayList alplace = clcheck.matchplace(strpro);
    cbplace.DataSource = alplace;
    cbplace.DisplayMember = "value";
    cbplace.ValueMember = "key";
}

⑥.界面真正的初始化(是不是用到了上面的两级联动的方法了,其实就是传参,没啥高明的)

改动省份城市变化

/// <summary>
/// 改动省份时城市变动
/// </summary>
private void cbpro_SelectedValueChanged(object sender, EventArgs e)
{
    //窗体第一次加载时会自动调用该事件,因为窗体加载时初始化了数据,而此时文本框里是空的,所以调用不了数据
    cbplace.DataSource = null;

    //begindata(cbpro.SelectedValue.ToString());
    if (choseplace > 1)
    {
        cbplace.DataSource = null;
        string strpro = cbpro.SelectedValue.ToString();
        begindata(strpro);
    }
    else
    {
        choseplace++;
    }
}

改动月份日期变化(如不写此变化会不会出现了个2月31日的情况呢)

/// <summary>
/// 改变月份时日期变动
/// </summary>
private void cbmonth_SelectedIndexChanged(object sender, EventArgs e)
{
    cbday.DataSource = null;
    cbday.Items.Clear();
    beginday();
    //begindata(cbpro.SelectedValue.ToString());
    //if (choseplace > 1)
    //{
    //    cbmonth.DataSource = null;
    //    string strpro = cbpro.SelectedValue.ToString();
    //    begindata(strpro);
    //}
    //else
    //{
    //    choseplace++;
    //}
}

改动年份时日期变化

/// <summary>
/// 改动年份时日期变动
/// </summary>
private void cbyear_SelectedIndexChanged(object sender, EventArgs e)
{
    cbday.DataSource = null;
    cbday.Items.Clear();
    beginday();
}

⑦.初始化我们的界面吧

private void frmidentity_Load(object sender, EventArgs e)
{
    //初始化省份数据源
    ArrayList alpro = clcheck.matchpro();
    cbpro.DataSource = alpro;
    cbpro.DisplayMember = "value";
    cbpro.ValueMember = "key";
    //设置默认省份
    cbpro.SelectedIndex = 0;
    //设置默认城市
    begindata(cbpro.SelectedValue.ToString());
    //设置默认年份
    beginyear();
    cbyear.SelectedIndex = 0;
    //设置默认月份
    beginmonth();
    cbmonth.SelectedIndex = 0;
    //设置默认天数
    beginday();
    cbday.SelectedIndex = 0;
    //设置默认性别
    beginsex();
    cbsex.SelectedIndex = 0;
    //ComboBox控件的DrawMode属性为:OwnerDrawVariable ,然后设置ItemHeight属性你要求的高度。不然下拉下来太长岂不是很像那个...你懂得的...
    //cbpro.Height = 20;
    cbpro.DropDownHeight = 100;
    cbplace.DropDownHeight = 100;
    cbyear.DropDownHeight = 100;
    cbmonth.DropDownHeight = 100;
    cbday.DropDownHeight = 100;

    this.Opacity = 0.95;
}
10.顺序码

写到这里,我们是不是忘了身份证号码中一个重要的3位顺序码呢,好吧,这里加上,不习惯可以改到cs类中去。顺序码=2位+性别1位。

//顺序码=2位+性别1位
//随机生成5个不重复的顺序码怎么玩?
private string beginturn()
{
    Random rm=new Random();
    int turnfirint = rm.Next(0, 100);
    string turnfirstr,turnsexstr;
    string[] str = new string[5];
    if (turnfirint < 10)
    {
        turnfirstr = "0" + turnfirint.ToString();
    }
    else
    {
        turnfirstr = turnfirint.ToString();
    }

    if (cbsex.SelectedIndex == 0)//男
    {
        turnsexstr = (2 * rm.Next(0, 5) + 1).ToString(); ;

    }
    else
    {
        turnsexstr = (2 * rm.Next(0, 5)).ToString();
    }

    return turnfirstr + turnsexstr;
}

PS:每次 随机生成5个 不同 顺序码是不是更刺激?不过貌似有点麻烦诶,有没有好的办法。

不要告诉我是把数字分成5等分,每次取出一个等份,连取5次,合起来5个。有兴趣的可以试试更高端的。

11.生成身份证号码(二代)

好了,总算把所有的准备工作做好,调用吧,生成结果,就是符合验证的号码。但是,不一定此号码存在,仅仅可以验证成功而已,其它的,就不在本篇博文范围了。

生成结果:

//生成结果
private string getresule()
{
    string strplace= cbplace.SelectedValue.ToString();
    string strbir,strmonth,strday;
    if(cbmonth.Text.Length<2)
    {
        strmonth="0"+cbmonth.Text.ToString();//选择的月是一位数要在前面加0
    }
    else
    {
        strmonth=cbmonth.Text.ToString();
    }
    if(cbday.Text.Length<2)
    {
        strday="0"+cbday.Text.ToString();
    }
    else
    {
        strday=cbday.Text.ToString();
    }

    strbir=cbyear.Text.ToString()+strmonth+strday;
    string strfir=strplace+strbir+beginturn();
    string strall=strfir+clcheck.checkcode(strfir);
    return strall;
}
lbresult.Items.Add(getresule());
12.添加特效

这样就结束了么,我们是不是还添加上一些小功能和特效呢?还有,cs中这个么多准备可不能浪费啊。

添加透明的提示窗体,效果如图:

copy成功,或者导出成功,是不是要加点啥呢,总比MessageBox漂亮吧。

要实现的功能:弹出透明窗体 渐变提示,自动渐变消失。

好了,我们在项目中 添加=>用户控件 ,我的命名为 F_Sign.cs

给控件上添加上label标签:lbsign,添加时间控件(渐变功能):timer1

在F_Sign.cs 的load添加如下代码:

private void Form_CopySign_Load(object sender, EventArgs e)
{
    this.timer1.Enabled = true;//激活时间控件
    this.Opacity = 1;//窗体透明度为1,即完全不透明
}

timer的Tick事件添加:

private void timer1_Tick(object sender, EventArgs e)
{
    if (this.Opacity > 0.5)
    {
        this.Opacity = this.Opacity - 0.08;
    }
    else
    {
        Close();
    }
    //意思就是当窗体的透明度大于0.5时透明度以0.08的速度递减;否则就关闭窗体
}

重载窗体函数,我们的提示信息狠多,肯定不能单一,所以,这就涉及到两个窗体之间的传参:

public F_Sign(int sign)
{ 
    InitializeComponent();
    this.Opacity = 0.9;
    if(sign==0)
    {
        lbsign.Text = "Failed!";
    }
    else if (sign == 1)
    {
        lbsign.Text = "Success!";
    }
    else if (sign == 2)
    {
        lbsign.Text = "Wrong number!";
    }
    else if (sign == 3)
    {
        lbsign.Text = "No chose!";
    }
}

当传过来的是0,我们理解我操作失败;1是成功;2是号码错误(用于验证身份证号码);3是你没有选择(用户复制时没有选择生成的特定号码)

窗体传值,从主窗体传到新建窗体,这个不难,大家可以自己学习。倒是从新窗体再把值传到主窗体,这个难度不小,用属性倒是不行的,这个需要深究了。好了,我们先上代码,萨后再在其它功能中添加主窗体和新窗体之间的传值,把你传晕。

复制功能和小特效展示:

/// <summary>
/// 复制
/// </summary>
private void btnCopy_Click(object sender, EventArgs e)
{
    try
    {
        Clipboard.SetDataObject(lbresult.SelectedItem);
        F_Sign frm = new F_Sign(1);//这不是就是上面的1么
        frm.ShowDialog();
    }
    catch (Exception err)
    { 
        //出现错误就复制失败
        F_Sign frm = new F_Sign(0);//0在这里
        frm.ShowDialog();                
    }
}

上图的提示效果完美完成,

13.添加移除功能

之所以要说到移除,有的同学说,很简单的码,清空Listbox不就OK了,这里我们要实现的是选中一行移除,移除之后我们的焦点一定还要在选中的行上面。但是这时如果移除的下面行没了呢?我们是不是还得把选中的焦点上移呢?

看代码:

/// <summary>
/// 移除选中
/// </summary>
private void btnRemove_Click(object sender, EventArgs e)
{
    //try{}catch{}捕获异常,话说去年没毕业的时候面试,还得一个C++的面试官刁难了一次,很恶心,自己不懂还来和我抬杠,诶,没办法诶。
    try
    {
        int indexbegin = lbresult.SelectedIndex;
        lbresult.Items.Remove(lbresult.SelectedItem);
        if (lbresult.Items.Count == 0)
        {
            return;
        }
        //MessageBox.Show(lbresult.SelectedIndex.ToString());
        if (indexbegin == 0)
        {
            lbresult.SelectedIndex = 0;
        }
        else
        {
            //选中的为最后一个
            if (indexbegin == lbresult.Items.Count - 1)
            {
                lbresult.SelectedIndex = indexbegin - 1;
            }
            else
            {
                //MessageBox.Show(lbresult.SelectedIndex.ToString());
                lbresult.SelectedIndex = indexbegin - 1;
            }
        }
    }
    catch (Exception err)
    {
        F_Sign frm = new F_Sign(3);
        frm.ShowDialog();
    }
}
14.添加导出文本功能

看到生成的这些号码,不导出保存一下,难道要我们一个个复制么,人性化点吧,给个导出功能,就是界面上的OutPut。

上代码,自己可以去学习命名空间 IO 下的一些方法吧,或许你能懂得更多。

/// <summary>
/// 导出结果
/// </summary>
private void btnout_Click(object sender, EventArgs e)
{
    if (lbresult.Items.Count > 0)
    {
        string str = "";
        StreamWriter sw = new StreamWriter("outid.txt");
        for (int i = 0; i < lbresult.Items.Count; i++)
        {
            //str += lbresult.Items[i] + "\n";
            sw.WriteLine(lbresult.Items[i]);
        }

        sw.Close();
    }
}
15.验证身份证号码

最后再来点,好吧,没完没了了。只是自己做点小工具,此篇博文仅仅是自己的 这次联系的知识总结。好吧,我们生成了号码,但是在文章开始做的那个类cs中,我们的方法,岂不是浪费了,要不要加个验证 身份证号码的小窗体呢。

添加一个新窗体:F_check.cs,相关控件如下图,不再一一说明。

这里涉及到的主要知识点:

传值:主窗体传到新建窗体(见12.添加特效,本功能不再演示,自己可以添加上写写),新窗体传到主窗体。

主窗体添加如下代码:

/// <summary>
/// Check
/// </summary>
private void btnCheck_Click(object sender, EventArgs e)
{
    //cbplace.DataSource = null;
    //string strpro = cbpro.SelectedValue.ToString();
    //begindata(strpro);
    F_check f2 = new F_check();

    f2.Owner = this;//传值关键,新窗体往主窗体回传值不能用属性
    f2.ShowDialog();
}

验证号码信息,当然,我们这里不是从主窗体复制的,你可以自己仿照 12 试试将选中的号码传到 新窗体 来验证,我们这里直接输入吧,

下面代码懒得整理,这不是重点,调用我们在文章开始写的方法即可。

private void btnCheck_Click(object sender, EventArgs e)
{
    string strid = txtid.Text.Trim();
    string strplace = "";
    string stryear="";
    string strmonth="";
    string strday="";
    string strturn="";
    string strsex="";

    ClassCheck clck = new ClassCheck();
    if(strid.Length==18)
    {
        //校验码
        if( clck.checkcode(strid.Substring(0,17))!=strid[17].ToString())
        {
            lbplace.Text = "place : wrong number!";
            lbdate.Text = "";
            lbsex.Text = "";
            lbturn.Text = "";
            F_Sign frm = new F_Sign(2);
            frm.ShowDialog();
            return;
        }


        strplace=clck.checkplace(strid.Substring(0,6));
        stryear=strid.Substring(6,4);
        //strplace=clck.checkplace(strid[0].ToString() + strid[1].ToString() + strid[2].ToString() + 
        //                        strid[3].ToString() + strid[4].ToString() + strid[5].ToString());
        //stryear = strid[6].ToString() + strid[7].ToString() + strid[8].ToString() + strid[9].ToString();

        if (strid[10].ToString() == "0")
        {
            strmonth = strid[11].ToString();
        }
        else
        {
            strmonth = strid[10].ToString() + strid[11].ToString();
        }

        if (strid[12].ToString() == "0")
        {
            strday = strid[13].ToString();
        }
        else
        {
            strday = strid[12].ToString() + strid[13].ToString();
        }

        strturn = strid[14].ToString() + strid[15].ToString() + strid[16].ToString();

        if (strid[16].ToString() == "1" || strid[16].ToString() == "3" || strid[16].ToString() == "5" || strid[16].ToString() == "7" || strid[16].ToString() == "9")
        {
            strsex = "男";
        }
        else
        {
            strsex = "女";
        }

        lbplace.Text ="place : "+strplace;
        lbdate.Text = "date : " + stryear + "-" + strmonth + "-" + strday;
        lbturn.Text = "turn : "+strturn;
        lbsex.Text = "sex : " + strsex;
    }

}

将我们输入的号码反填到主窗体的ListBox中,至于本号码对不对,想研究的童鞋可以自己做个判断。

private void btnAdd_Click(object sender, EventArgs e)
{
    F_main frm = (F_main)this.Owner;
    ((ListBox)frm.Controls["lbresult"]).Items.Add(this.txtid.Text.Trim());
    this.Close();
}

这样,我们图上的功能就基本实现了。

16.总结

实在受不了,一写,发现还有狠多需要实现,入坑了,坚决不继续写了,这孩子,越想越多了。

本篇博文,仅仅是自己学习了一些字典和哈希表的小知识,顺便,想体验一下,没想到搞了这么多。

知识总结如下,通过本文,你需要加深如下了解:

①哈希表,字典,二维数组 的使用(超大数据的提取和写入中作为缓存,后面例子将用到);

② \文件写入和读取(后面将做个超简单的文件浏览器雏形);

③下拉表绑定和多级联动;

④窗体之间的传值,正传和反传;

⑤其它

17.参考资料

github上源代码

注:请勿将工具用于非法用途,否则后果自负。

本文最后修订时间:2017-11-15

退出移动版