ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 10338|回复: 10

[分享] 汉字数字与阿拉伯数字中文格式日期的转换

[复制链接]

TA的精华主题

TA的得分主题

发表于 2012-6-22 12:33 | 显示全部楼层 |阅读模式
本帖最后由 sylun 于 2012-6-22 14:12 编辑

有感于近两天关于中文格式日期转换的帖子(http://club.excelhome.net/thread-484569-1-1.html),花了点时间写了一段转换代码。其基本思路是对查找到的特征文本,经简单筛选再结合Isdate函数的判断来确定有效日期格式文本,最后利用Quote域的日期图片开关来进行相应转换。通过编写这段代码,对Isdate和Datevalue等函数以及Quote域对中文日期的识别有了更多的了解。其适用范围见代码中的相关说明。
欢迎测试并提出改进意见。
  1. Sub DateFormatConverting()
  2.     ''有选定内容只处理选定部分,否则处理全文档
  3.     ''如选定内容不超过一个段落,则不弹出对话框选择转换类型,程序将根据段落选定内容是否有阿拉伯数字来自动选择转换格式
  4.     ''只转换含“年月日”、“年月”、“月日”或仅为“××××年”四种格式的有效日期文本
  5.     Dim myRange As Range
  6.     Dim a As Integer
  7.     Dim sz As String
  8.     Dim txt As String
  9.     Dim rq As String
  10.     Dim e As Long
  11.     Dim nf As String
  12.     Dim codetext As String
  13.     Dim switch As String
  14.     Dim n As Integer
  15.    
  16.     With Selection
  17.         If .Type = wdSelectionNormal And .Paragraphs.Count = 1 Then
  18.             If .Text Like "*#*" Then a = 6 Else a = 7
  19.             If .Text Like "*[月日]" Then .End = .End + 1 '简单预防性措施
  20.         Else
  21.             a = MsgBox("转为汉字数字日期请按“是”,转为阿拉伯数字日期请按“否”", vbYesNoCancel, "汉字数字与阿拉伯数字中文日期格式转换")
  22.         End If
  23.         Set myRange = IIf(.Type = wdSelectionIP, ActiveDocument.Content, .Range)
  24.     End With
  25.     If a = 2 Then Exit Sub
  26.     sz = IIf(a = 6, "[0-9", "[〇○一二三四五六七八九十")
  27.     Application.ScreenUpdating = False
  28.     With myRange.Duplicate.Find
  29.         .Text = sz & "年月日]{4,}"  '不想转换仅为“××××年”的格式文本时可用 .Text = sz & "]@[年月]" & sz & "月日]{2,}"
  30.         .MatchWildcards = True
  31.         Do While .Execute
  32.             With .Parent
  33.                 If .Start >= myRange.End - 1 Then Exit Do
  34.                 If .Text Like "*?[年月]*" Then
  35.                     Do While .Text Like "*" & sz & "][年月日]" = False
  36.                         .End = .End - 1
  37.                     Loop
  38.                     txt = Replace(.Text, "〇", "○")
  39.                     If Mid(txt, 3, 1) = "年" Then
  40.                         nf = DateValue(Left(txt, InStr(txt, "月")))
  41.                         If a = 7 Then nf = IIf(nf Like "1*", "一九", "二○") Else nf = Empty
  42.                     End If
  43.                     If txt Like "????年" Then
  44.                         txt = txt & IIf(a = 6, "1月", "一月")
  45.                         switch = IIf(a = 6, " \@ EEEE年", " \@ yyyy年")
  46.                     ElseIf a = 7 Then
  47.                         switch = IIf(InStr(txt, "日"), IIf(InStr(txt, "年"), " \@ yyyy年M月d日", " \@ M月d日"), " \@ yyyy年M月")
  48.                     Else
  49.                         switch = IIf(InStr(txt, "日"), IIf(InStr(txt, "年"), " \@ EEEE年O月A日", " \@ O月A日"), " \@ EEEE年O月")
  50.                     End If
  51.                     rq = Mid(txt, InStr(txt, "月") + 1)
  52.                     If Len(rq) = 3 Then
  53.                         rq = Left(txt, InStr(txt, "月")) & Replace(rq, "十", "○")
  54.                     ElseIf Len(rq) > 3 Then
  55.                         rq = Left(txt, InStr(txt, "月")) & Replace(rq, "十", "")
  56.                     Else
  57.                         rq = txt
  58.                     End If
  59.                     If IsDate(rq) Then
  60.                         codetext = Chr(34) & nf & IIf(InStr(txt, "年"), "", IIf(a = 7, "二〇一二年", "2012年")) & txt & Chr(34)
  61.                         If nf <> Empty Then switch = Replace(switch, "yyyy年", "yy年")
  62.                         With ActiveDocument.Fields.Add(.Duplicate, wdFieldQuote, codetext & switch, False)
  63.                             e = Len(.Result.Text)
  64.                             n = n + 1
  65.                             .Unlink
  66.                         End With
  67.                         If Mid(txt, 3, 1) = "年" And a = 6 Then
  68.                             ActiveDocument.Range(.Start, .Start + 2).Delete
  69.                             e = e - 2
  70.                         End If
  71.                         .Start = .Start + e
  72.                         nf = Empty
  73.                         e = 0
  74.                     End If
  75.                 End If
  76.             End With
  77.         Loop
  78.     End With
  79.     If myRange.Paragraphs.Count > 1 Then MsgBox "OK!共转换了" & n & "个相关日期文本。"
  80.     Application.ScreenUpdating = True
  81. End Sub
复制代码

TA的精华主题

TA的得分主题

发表于 2012-6-22 13:36 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
请问:这个怎么用啊?能不能上传一个附件呀??

TA的精华主题

TA的得分主题

发表于 2012-6-22 13:25 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
代码包含了多种方法,考虑了方方面面。值得收藏学习!

TA的精华主题

TA的得分主题

发表于 2012-6-23 06:29 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 守柔 于 2012-6-23 06:53 编辑

sylun兄的代码很好。
其中,Range.Duplicate 属性,Quote域对于日期的转换,就是很好的见证。
我未对代码进行测试,只是读了数遍代码,提几个建议:
1.就查找而言,使用Range.Duplicate固然很好地解决了这个动中取静的Range的问题,但 If .Start >= myRange.End - 1 Then Exit Do在每次查换中均需判断,是否必须这样进行?有没有考虑如果增设一个书签,在这个书签对象的Range中查找替换,是否也可以或者更合理一些?如果是这样,是不是其中的
With ActiveDocument.Fields.Add(.Duplicate, wdFieldQuote, codetext & switch, False)
                            e = Len(.Result.Text)
                            n = n + 1
                            .Unlink
                        End With
                        If Mid(txt, 3, 1) = "年" And a = 6 Then
                            ActiveDocument.Range(.Start, .Start + 2).Delete
                            e = e - 2
                        End If
                        .Start = .Start + e
可以更简捷一些,即针对rngFound进行Fields.Add,然后更改域结果,如:
    Set rngField = rngFound.Fields.Add(rngFound, wdFieldQuote, Chr$(34) & "2012-5-12" & Chr$(34) & " \@ EEEE年O月A日", False).Result
....
    rngField.Text = Mid$(rngField.Text, 3)
2.对于一个较好的代码,要考虑错误处理程序。
3.规范变量的命名很重要,它可以提高代码可读性.比如过程中的a,e等.有关变量命名的专门文档可搜索本论坛等.

TA的精华主题

TA的得分主题

发表于 2012-6-23 19:53 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 sqhsqhli 于 2012-6-23 20:27 编辑

学然后知不足,向楼主版主致敬.  
测试遇到当两个以上日期连续出现时,不能转换。。。当然从文本内容上来说不大可能出现这样的情况

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-24 09:34 | 显示全部楼层
守柔 发表于 2012-6-23 06:29
sylun兄的代码很好。
其中,Range.Duplicate 属性,Quote域对于日期的转换,就是很好的见证。
我未对代码 ...

谢谢老大关注与指导。我平时写的代码因行数不多,任务与方法都不算复杂,加上想偷点懒,通常只讲究一下逻辑层次,变量命名确欠规范,说明文字也不多。
其实,上面的代码有其局限性,对无效的中文日期格式文本的处理有不确定性,主要原因源于Quote域对其识别与转换上存在自以为是的情形。另外,因其有插入域与断开链接两个编辑运作,效率不算高。
以下代码尝试另一种思路,不借用Quote域,只用Isdate函数判别格式文本的有效性并进行相应转换,并兼顾程序的可读性。
  1. Sub DateFormateConverting2()
  2.     ''有选定内容只处理选定部分,否则处理全文档
  3.     ''如选定内容不超过一个段落,则不弹出对话框选择转换类型,程序将根据段落选定内容是否有阿拉伯数字来自动选择转换格式
  4.     ''只转换含“年月日”、“年月”、“月日”或仅为“××××年”四种格式的有效日期文本
  5.     Const strChinesenum As String = "○一二三四五六七八九"
  6.     Dim rngFind As Range
  7.     Dim IntResponse As Integer
  8.     Dim strFindnum As String
  9.     Dim strFoundtext As String
  10.     Dim strDatetext As String
  11.     Dim strChineselistnum(31) As String
  12.     Dim i As Integer
  13.     Dim j As Integer
  14.     Dim n As Integer
  15.     Dim strYmd(2) As String
  16.     Dim strConvertYmd(2) As String
  17.    
  18.     On Error GoTo Exit_sub
  19.     For i = 0 To 31  '将0至31之间的中文序数赋值给数组
  20.         If i < 10 Then
  21.             strChineselistnum(i) = Mid(strChinesenum, i + 1, 1)
  22.         ElseIf i Mod 10 > 0 Then
  23.             strChineselistnum(i) = IIf(i < 20, "十", Mid(strChinesenum, Int(i / 10) + 1, 1) & "十") & Mid(strChinesenum, i Mod 10 + 1, 1)
  24.         Else
  25.             strChineselistnum(i) = IIf(i < 20, "十", Mid(strChinesenum, Int(i / 10) + 1, 1) & "十")
  26.         End If
  27.     Next
  28.     With Selection  '确定查找处理区域及转换类型
  29.         If .Type = wdSelectionNormal And .Paragraphs.Count = 1 Then
  30.             IntResponse = IIf(.Text Like "*#*", 6, 7)
  31.             If .Text Like "*[月日]" Then .End = .End + 1 '普通预防性措施
  32.         Else
  33.             IntResponse = MsgBox("转为汉字数字日期请按“是”,转为阿拉伯数字日期请按“否”", vbYesNoCancel, "汉字数字与阿拉伯数字中文日期格式转换")
  34.         End If
  35.         Set rngFind = IIf(.Type = wdSelectionIP, ActiveDocument.Content, .Range)
  36.     End With
  37.     If IntResponse = 2 Then Exit Sub
  38.     strFindnum = IIf(IntResponse = 6, "[0-9", "[〇○一二三四五六七八九十")
  39.    
  40.     Application.ScreenUpdating = False
  41.     With rngFind.Duplicate.Find  '查找与处理
  42.         .Text = strFindnum & "年月日]{4,}"  '不想转换仅为“××××年”的格式文本时可用 .Text = strFindnum & "]@[年月]" & strFindnum & "月日]{2,}"
  43.         .MatchWildcards = True
  44.         Do While .Execute
  45.             With .Parent
  46.                 If .Text Like "*?[年月]*" Then
  47.                     Do While .Text Like "*" & strFindnum & "][年月日]" = False
  48.                         .End = .End - 1
  49.                     Loop
  50.                     strFoundtext = Replace(.Text, "〇", "○")
  51.                     If InStr(strFoundtext, "年") Then strYmd(0) = Split(strFoundtext, "年")(0)
  52.                     If InStr(strFoundtext, "月") > 0 Then strYmd(1) = Split(strFoundtext, "月")(0)
  53.                     If InStr(strYmd(1), "年") > 0 Then strYmd(1) = Split(strYmd(1), "年")(1)
  54.                     If InStr(strFoundtext, "日") > 0 Then strYmd(2) = Replace(Split(strFoundtext, "月")(1), "日", "")
  55.                     If IntResponse = 6 Then  '转为汉字数字格式
  56.                         strDatetext = IIf(strYmd(0) <> "", Join(strYmd, "-"), "2012" & Join(strYmd, "-"))
  57.                         If strDatetext Like "*--" And Len(strDatetext) = 6 Then strDatetext = Replace(strDatetext, "--", "-1") _
  58.                             Else If strDatetext Like "*-" Then strDatetext = Left(strDatetext, Len(strDatetext) - 1)
  59.                         If IsDate(strDatetext) Then
  60.                             If strYmd(0) <> "" Then
  61.                                 For i = 1 To Len(strYmd(0))
  62.                                     strConvertYmd(0) = strConvertYmd(0) & strChineselistnum(Mid(strYmd(0), i, 1))
  63.                                 Next
  64.                                 strConvertYmd(0) = strConvertYmd(0) & "年"
  65.                             End If
  66.                             If strYmd(1) <> "" Then strConvertYmd(1) = strChineselistnum(strYmd(1)) & "月"
  67.                             If strYmd(2) <> "" Then strConvertYmd(2) = strChineselistnum(strYmd(2)) & "日"
  68.                             .Text = Join(strConvertYmd, "")
  69.                             n = n + 1
  70.                         End If
  71.                     Else  '转为阿拉伯数字格式
  72.                         For i = 1 To Len(strYmd(0))
  73.                             For j = 0 To 9
  74.                                 If Mid(strYmd(0), i, 1) = strChineselistnum(j) Then
  75.                                     strConvertYmd(0) = strConvertYmd(0) & j
  76.                                     Exit For
  77.                                 End If
  78.                                 
  79.                             Next
  80.                         Next
  81.                         If strYmd(0) <> "" Then strConvertYmd(0) = strConvertYmd(0) & "年"
  82.                         For i = 1 To 2
  83.                             For j = 0 To 31
  84.                                 If strYmd(i) = strChineselistnum(j) Then
  85.                                     strConvertYmd(i) = j & IIf(i = 1, "月", "日")
  86.                                     Exit For
  87.                                 End If
  88.                             Next
  89.                         Next
  90.                         strDatetext = Join(strConvertYmd, "")
  91.                         If strDatetext Like "????年" Then strDatetext = strDatetext & "1月"
  92.                         If IsDate(strDatetext) Then
  93.                             .Text = Join(strConvertYmd, "")
  94.                             n = n + 1
  95.                         End If
  96.                     End If
  97.                 End If
  98.                 .SetRange .End, rngFind.End
  99.                 strDatetext = ""
  100.                 Erase strYmd
  101.                 Erase strConvertYmd
  102.             End With
  103.         Loop
  104.     End With
  105.    
  106.     If rngFind.Paragraphs.Count > 1 Then MsgBox "OK!共转换了" & n & "个相关日期文本。" _
  107.         Else If n = 0 Then MsgBox "找不到有效中文日期文本!", vbInformation
  108.     Application.ScreenUpdating = True
  109.     Exit Sub
  110.    
  111. Exit_sub:
  112.     MsgBox "程序发生意外,终止执行!"
  113. End Sub
复制代码

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-24 09:48 | 显示全部楼层
sqhsqhli 发表于 2012-6-23 19:53
学然后知不足,向楼主版主致敬.  
测试遇到当两个以上日期连续出现时,不能转换。。。当然从文本内容上来说 ...

谢谢sqhsqhli 兄关注。因这样的两个日期只成为一个匹配。要再区分应该也行,只是从实际文本中似难以出现。

TA的精华主题

TA的得分主题

 楼主| 发表于 2012-6-24 10:06 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
嘉—嘉 发表于 2012-6-22 13:36
请问:这个怎么用啊?能不能上传一个附件呀??

如果不会用,上传附件也解决不了您的问题。建议在本版中查找一下如何将宏代码放入文档并运行宏,如http://club.excelhome.net/forum.php?mod=viewthread&tid=727438

TA的精华主题

TA的得分主题

发表于 2012-6-24 15:28 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
你好,我这里提示编译错误

TA的精华主题

TA的得分主题

发表于 2014-8-13 15:25 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
出现异常,请大家帮看看。系统为windows 8 +office 2013
捕获.PNG
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2025-1-17 00:14 , Processed in 0.026472 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表