农转公/公转农 System.Globalization.ChineseLunisolarCalendar 农历转公历/公历转农历

项目中有一个生日短信提醒功能,需要每年提醒。选农历, 每年提醒, 第二年的公历是不一样的,所以每一年的都需要自己计算。

设计的要求 ,他们说因为年纪大的人是只记得农历的。。。

网上资料不少,公历转农历现成的一堆。都是用微软的System.Globalization.ChineseLunisolarCalendar类写的,
但是农历转公历的很少,也有,但都是只提到方法的调用,比如下面:
 20151122234809
正确的应该是1982-10-12 。由于 并没有详细说到关键的闰月计算, 所以起初很困惑,以为计算不准确。

20151122235510

检查全年的月份,发现有因为有闰月的情况,有润月则应该从该闰月起月份自动加一, 如1982年润四月,或则闰五月为6月,后面的月加一处理。
方便理解自己做个对照图:

20151122233022

正确的方法是,要先计算当年农历生日之前的月份有没有闰月,

有了就 直接构造农历日期对象是就把农历的月+1 为9月:

20151122235952

只要明白闰月这一点,其实就很简单了!

///////////
//公历转农历
///////////
            DateTime date = Convert.ToDateTime(textBox1.Text);	//格式:2000-1-1
            ChineseLunisolarCalendar cc = new ChineseLunisolarCalendar();

            if (date > cc.MaxSupportedDateTime || date < cc.MinSupportedDateTime)  
                MessageBox.Show("参数日期时间不在支持的范围内,支持范围:"+cc.MinSupportedDateTime.ToShortDateString()+"到"+cc.MaxSupportedDateTime.ToShortDateString());
            
            int year = cc.GetYear(date);
            int month = cc.GetMonth(date);
            int dayOfMonth = cc.GetDayOfMonth(date);
            int leapMonth = cc.GetLeapMonth(year);
            bool isLeapMonth = cc.IsLeapMonth(year, month);
            bool isLeapYear = cc.IsLeapYear(year);

            if (isLeapMonth || isLeapYear && month >= leapMonth)
                month -= 1;

            textBox2.Text = string.Concat(year, "-", month, "-", dayOfMonth);
///////////
//农历转公历
///////////

	    ChineseLunisolarCalendar cc = new ChineseLunisolarCalendar();
            DateTime date = Convert.ToDateTime(textBox2.Text);	//格式:2000-1-1
            int MonthsInYear = cc.GetMonthsInYear(date.Year);
            int LeapMonth = cc.GetLeapMonth(date.Year, 1);
            bool isLeapMonth = cc.IsLeapMonth(date.Year, date.Month);
            bool isLeapYear = cc.IsLeapYear(date.Year);

            if (isLeapMonth)
                date = cc.ToDateTime(date.Year, date.Month - 1, date.Day, 0, 0, 0, 0);
            else if(date.Month > LeapMonth)
                date = cc.ToDateTime(date.Year, date.Month + 1, date.Day, 0, 0, 0, 0);
            else
                date = cc.ToDateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
            
            textBox1.Text = date.ToString("yyyy-MM-dd");

这是一个WinForm做的的实例Demo: WindowsFormsApplication1

通过动态字符串获取变量值 & 获取变量名称

一段实例代码, 在 c#中通过 Linq 取变量的名称, 以及 将字符串转为变量名,通过字符串给变量赋值.

        string strApp = "app";
        public string app = "AAA";
        public string strTest = "TEST";
        protected void Button1_Click(object sender, EventArgs e)
        {

            //通过字符串获得变量值
            string aaa1 = this.GetType().GetField("app").GetValue(this).ToString();
            //或者
            string aaa2 = this.GetType().GetField(strApp).GetValue(this).ToString();
            //通过给变量赋值
            this.GetType().GetField("strTest").SetValue(this, "C#123");
            //新的值
            string bbb = this.GetType().GetField("strTest").GetValue(this).ToString();

            //获取变量名称
            string ccc = GetVarName(p=>this.strTest);
        }

        //获取变量名称
        public static string GetVarName(System.Linq.Expressions.Expression<Func<string, string>> exp)
      {
            return ((System.Linq.Expressions.MemberExpression)exp.Body).Member.Name;
      }

 

C#、PHP、Python 运算符的优先级

C#、PHP、Python 运算符的优先级

C#  运算符优先级

优先级
类别
运算符
1
基本
(x) x.y f(x) a[x] x++ x――new typeof sizeof checked unchecked
2
单目
+ - ! ~ ++x ――x (T)x
3
乘法与除法
* / %
4
加法与减法
+ -
5
移位运算
<< >>
6
关系运算
< > < = >=
7
条件等
= = ! =
8
位逻辑与
&
9
位逻辑异或
^
10
位逻辑或
|
11
条件与
&&
12
条件或
13
条件
?:
14
赋值
= *= /= %= += -= <<= >>= &= ^= |=

 

上表源自:  http://baike.baidu.com/view/262524.htm#4

C# 提供大量运算符,这些运算符是指定在表达式中执行哪些操作的符号。             ==, !=, &lt;, &gt;, &lt;=, &gt;=, binary +, binary -, ^, &amp;,’ xml:space=”preserve”>整型运算包括 ==、!=、<、>、<=、>=、binary +、binary -、^、& |~, ++, –, and sizeof() are generally allowed on enumerations.’ xml:space=”preserve”>、~、++、– 和 sizeof(),通常在枚举时允许这些运算。  overloaded by the user, thus changing their meaning when applied to a user-defined type.’ xml:space=”preserve”>此外,很多运算符可被用户重载,由此在应用到用户定义的类型时更改这些运算符的含义。

下表列出了按发型版本不同的 C# 运算符:

 

PHP运算符优先级

 

 
结合方向 运算符 附加信息
非结合 clone new clone 和 new
[ array()
非结合 ++ -- 递增/递减运算符
非结合 ~ - (int) (float) (string) (array) (object) (bool) @ 类型
非结合 instanceof 类型
右结合 ! 逻辑操作符
* / % 算术运算符
+ - . 算术运算符 和 字符串运算符
<< >> 位运算符
非结合 < <= > >= <> 比较运算符
非结合 == != === !== 比较运算符
& 位运算符 和 引用
^ 位运算符
| 位运算符
&& 逻辑运算符
|| 逻辑运算符
? : 三元运算符
= += -= *= /= .= %= &= |= ^= <<= >>= 赋值运算符
and 逻辑运算符
xor 逻辑运算符
or 逻辑运算符
, 多处用到

 

 

Python 运算符优先级

 

这个表给出Python的运算符优先级(从低到高).

从最低的优先级(最松散地结合)到最高的优先级(最紧密地结合)。

这意味着在一个表达式中,Python会首先计算表中较下面的运算符,然后在计算列在表上部的运算符。

 
运算符 描述
lambda Lambda表达式
or 布尔“或”
and 布尔“与”
not x 布尔“非”
in,not in 成员测试
is,is not 同一性测试
<,<=,>,>=,!=,== 比较
| 按位或
^ 按位异或
& 按位与
<<,>> 移位
+,- 加法与减法
*,/,% 乘法、除法与取余
+x,-x 正负号
~x 按位翻转
** 指数
x.attribute 属性参考
x[index] 下标
x[index:index] 寻址段
f(arguments...) 函数调用
(experession,...) 绑定或元组显示
[expression,...] 列表显示
{key:datum,...} 字典显示
'expression,...' 字符串转换

 

上两表源自:  http://tool.oschina.net/commons?type=6#php_

 

C#中用正则表达式取页面下拉菜单(select)中的值

 

给几个在C#中,使用正则表达式取页面下拉菜单(select)中的值示例:

//取html中全部 select 的 name
Regex reg_name = new Regex(@"(?<=<select name=\"").*?(?=\"")");

//取html中全部<select>项的值
Regex reg_select = new Regex("(?is)<select name=*.*?>]*.*?</select>");

//取html中一个 select name 等于"Status"的值
Regex status = new Regex(@"(?is)<select name=\""status\"">]*.*?</select>");

 

一下是一段完整的代码和方法,取html中一个下拉菜单 select name 等于”Status”的中值,添加到DropDownList中:

        string strDoc = (你的html);

        //取html中一个下拉菜单 select name 等于"Status"的中值
        Regex status = new Regex(@"(?is)<select name=\""status\"">]*.*?</select>");
        MatchCollection mc_status = status.Matches(strDoc);
        getSelectOptions(mc_status, cmbStatus);

        /// <summary>
        /// 取select对列表复制
        /// </summary>
        /// <param name="selected"></param>
        /// <param name="cmb"></param>
        void getSelectOptions(MatchCollection selected, ComboBox cmb)
        {
            if (selected.Count < 1)
                return;
            txtValues.Text = "";
            txtValues.Text = selected[0].Value.Replace("</option>", Environment.NewLine);
            string tmpTxt = "";
            foreach (string s in txtValues.Lines)
            {
                if (s == "")
                    continue;
                string a = "";
                a = s.Replace("\"", "").Replace("<option value=\"", "");
                int x = a.LastIndexOf(">");
                tmpTxt += a.Substring(x + 1) + Environment.NewLine;
            }
            txtValues.Text = tmpTxt.Trim();
            cmb.Items.Clear();
            cmb.Items.AddRange(txtValues.Lines);
            cmb.SelectedIndex = 0;
            cmb.Size = cmb.PreferredSize;
        }

 

推荐一个正则表达式测试/验证工具 – http://as32.net/blog/8814

 

推荐一个正则表达式测试/验证工具

这几天代码里用到很多正则表达式,需要验证,直接在程序里调试太麻烦。

比如:C#中用正则表达式取页面下拉菜单(select)中的值 – http://as32.net/blog/8815

 

找到了这个验证工具:

正则表达式测试器 – http://deerchao.net/tools/regex_tester/index.htm
说明:该工具允许你测试和分析正则表达式。

解决 webBrowser DocumentCompleted 的多次调用

winform中使用webBrowser抽取页面中的一些数据。断点“webBrowser1_DocumentCompleted”发现,跑进来了好多次。

DocumentCompleted执行多次,跟踪发现ReadyState状态不一样,分别是Intercative和Complete。

而MSDN对这两种状态值的解释是:

  • Complete该控件已完成新文档及其所有内容的加载;
  • Interactive该控件已经加载足够的文档以允许有限的用户交互,比如单击已显示的超链接。

增加判断“ReadyState”之后继续,DocumentCompleted仍然执行了两次,但ReadyState状态一样都是Complete。再查原因。

MSDN对其解释是在多个的帧的情况下DocumentComplete获取触发多次。并非每个框架将触发此事件,但触发DownloadBegin事件的每个框架将触发相应的DocumentComplete事件。

 

最后webBrowser1_DocumentCompleted中的代码是:

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            string BrowserUrl = webBrowser1.Url.ToString();

            if (String.IsNullOrEmpty(BrowserUrl)) //检查未赋值或空值
                return;
            if (BrowserUrl.Equals("about:blank")) //是否为空白页
                return;
            if (webBrowser1.ReadyState != WebBrowserReadyState.Complete)  //状态为完成
                return;
            if (e.Url.ToString() != BrowserUrl)  //检查事件url和webBrowser的url
                return;
            if (webBrowser1.DocumentText == "")
                return;

            ... ...
        }

 

还有一点,就是窗体打开就加载webBrowser1,如放在 Form_Load 会使程序界面加载很慢,建议放在 Form_Shown中(每当窗体第一次显示时发生)。