Sub 詞牌斷句()
Dim p As Paragraph, Char, c, i As Long
Dim db As New adodb.Connection, DbFullname As String, 詞牌rst As New adodb.Recordset
Dim 詞牌 As String, CiPaiParagraph As Paragraph
Dim docText As String, myRngFlag As Boolean, UndoTimes As Long
Dim ds As Date, de As Date
Dim 詞文 As String, j As Integer, L As Byte
Dim DiaoShi As String, DiaoShiItem As String, DiaoShiCharscount As Integer, DiaoShiCount As Long
Dim addParagraphCount As Long
On Error GoTo ErrH
DbFullname = dbFile("詞學韻律資料庫*.xlsm", "")
If Dir(DbFullname) = "" Then
DbFullname = InputBox("請輸入<歷代詞作韻律資料庫>全檔名(含路徑與副檔名)", "詞牌斷句", DbFullname)
End If
If DbFullname = "" Then Exit Sub
If MsgBox("執行此次""詞牌斷句標韻"",將會清除文本中任何符號(含空格,數字,英文)", vbExclamation + vbOKCancel, "<詞牌斷句標韻>程序") = vbCancel Then Exit Sub
ds = Timer
db.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & DbFullname & ";" & _
"Extended Properties=""Excel 8.0;HDR=Yes;"";"
Char = Array("◎", "。", "、", ",", "!", ";", ".", ".", """", "‘", "’", "『", "』", "「", "」", "?", "?", "〞", "〝", "!", " ", "…", _
" ", "[", "]", "〔", "〕", "﹝", "﹞", "﹝", "﹞", "(", ")", "{", "}", "{", "}", "‵", "'", _
"@", "#", "$", "%", "^", "&", "*", "_", "-", "+", "=", "|", ":", "/", "~", "1", "2", "3", "4", "5", "6", "7", _
"8", "9", "0", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", _
"w", "x", "y", "z", "﹗", "﹑", "﹖", VBA.Chr(9), ChrW(&H2460), ChrW(&H2461), ChrW(&H2462), ChrW(&H2463), ChrW(&H2464), _
ChrW(&H2465), ChrW(&H2466), ChrW(&H2467), ChrW(&H2468), ChrW(&H2469), ChrW(&H246A), ChrW(&H246B), ChrW(&H246C), _
ChrW(&H246D), ChrW(&H246E), ChrW(&H246F), ChrW(&H2470), ChrW(&H2471), ChrW(&H2472), ChrW(&H2473), ChrW(&H2474), ChrW(&H2475) _
, ChrW(&H2476), ChrW(&H2477), ChrW(&H2478), ChrW(&H2479), ChrW(&H247A), ChrW(&H247B), ChrW(&H247C), ChrW(&H247D), _
ChrW(&H247E), ChrW(&H247F), ChrW(&H2480), ChrW(&H2481), ChrW(&H2482), ChrW(&H2483), ChrW(&H2484), ChrW(&H2485) _
, ChrW(&H2486), ChrW(&H2487))
With d
'先清理文本
docText = .Content
With .Content.Find
.ClearAllFuzzyOptions: .ClearFormatting: .ClearHitHighlight
For Each c In Char
' If c = "﹑" Then Stop
If InStr(docText, c) > 0 Then
UndoTimes = UndoTimes + 1
.Execute c, False, False, False, , , , , , "", wdReplaceAll
End If
Next
End With
docText = Empty: Char = Empty
For Each p In .Paragraphs '前一段是詞牌,後一段是詞文
If addParagraphCount <> 0 Then
addParagraphCount = addParagraphCount - 1
GoTo NextParagraph
End If
If p.Range = Chr(13) Then GoTo NextParagraph '如果是一個空段
i = i + 1 ' i 是專門用來判斷詞牌段落的
If i Mod 2 = 1 Then '如果是詞牌段落
p.Style = "標題 1"
With p.Range.Font
.Size = 18
'.Bold = True
'.Size = 18
.NameFarEast = "標楷體"
End With
Set CiPaiParagraph = p '可見 Paragraph和Range不同,Range變數設定了就會跟著原Range跑,可見是reference type,而Paragraph 則不會,是(Value Type) instantiated object 執行個體
詞牌 = Mid(p.Range, 1, Len(p.Range) - 1)
詞牌rst.Open "select Top 1 詞牌 from [工作表1$] where strcomp(詞牌,""" & 詞牌 & """)=0;", db, adOpenKeyset, adLockReadOnly, 1 ' Top 1 、DISTINCT 和二者皆無者,取得記錄效率差不多
If 詞牌rst.RecordCount > 0 Then '工作表有詞牌時
詞牌rst.Close
GoTo NextParagraph
End If
Else '如果是詞文段落
If 詞牌rst.State = adStateOpen Then 詞牌rst.Close
詞牌rst.Open "select DISTINCT 詞牌,調式,字數 from [工作表1$] GROUP BY 詞牌,調式,字數 HAVING strcomp([詞牌],""" & 詞牌 & """)=0 and strcomp([字數],""" & CStr(p.Range.Characters.Count - 1) & """)=0", db, adOpenKeyset, adLockReadOnly, 1
DiaoShiCount = 詞牌rst.RecordCount
If DiaoShiCount > 0 Then
myRngFlag = True
詞文 = Mid(p.Range, 1, Len(p.Range) - 1)
If DiaoShiCount > 1 Then 'Stop
' With p.Previous.Range.Characters.last
' .InsertBefore " "
' With .Previous
' .Font.Size = 12
' .Bold = True
' .Text = "(共" & DiaoShiCount & "式)"
' End With
' End With
CiPaiParagraph.Range.Characters.last.InsertBefore " " '上面不行此下行,可見 每呼一次 p 即又一個 new p,如 C#裡的 string 或 instance 執行個體 一樣 。這個動作其實是建構了另一個 p 物件執行個體,而不是改了p
With CiPaiParagraph.Range.Characters.last.Previous '既然是重新建構一個 p 物件,那麼若不參照此新物件,此新物件便無用了。再 call 一次 p,即取得這個新的 p,而原p 即如舊的 string 被回收一樣
.Font.Size = 12
.Bold = True
.Text = "(共 " & DiaoShiCount & "式)" 'p.Parent.Range(p.Previous.Range.Characters.last.End- len("(共" & DiaoShiCount & " 種調式:))-1,p.Previous.Range.Characters.last.previous.end).Font.Bold = True
End With
End If
Do
'開始標韻
DiaoShi = 詞牌rst("調式").Value
L = Len(DiaoShi)
For j = 1 To L '檢查調式的迴圈
DiaoShiItem = Mid(DiaoShi, j, 1) '取得調式中的各個單元元素
If IsNumeric(DiaoShiItem) Then '句讀
DiaoShiCharscount = DiaoShiCharscount + CByte(DiaoShiItem)
If DiaoShiCharscount > p.Range.Characters.Count - 1 Then
If MsgBox("調式與字數不合!是否繼續?", vbOKCancel + vbExclamation) = vbCancel Then
p.Range.Paragraphs.Add
If Not p.Next Is Nothing Then
Set p = p.Next
End If
p.Range.Text = DiaoShi & Chr(13)
Set p = p.Previous '因為插入了 chr(13) 分段符號,故須再回到前一段
'addParagraphCount = addParagraphCount + 1 '加了2個段落
p.Range.Font.Name = "Calibri"
p.Range.HighlightColorIndex = wdYellow
p.Range.Select
GoTo ExitExe
Else
p.Range.HighlightColorIndex = wdYellow
GoTo nextRecord
End If
End If
If j + 1 <= L Then
If Mid(DiaoShi, j + 1, 1) = "." Then
p.Range.Characters(DiaoShiCharscount).InsertAfter "," '暫訂用此符號
Else
p.Range.Characters(DiaoShiCharscount).InsertAfter "。" '暫訂用此符號
p.Range.Characters(DiaoShiCharscount + 1).Font.ColorIndex = wdRed '標韻色彩
End If
Else
p.Range.Characters(DiaoShiCharscount).InsertAfter "。" '最後一字應都是韻腳。暫訂用此符號
p.Range.Characters(DiaoShiCharscount + 1).Font.ColorIndex = wdRed '標韻色彩
End If
DiaoShiCharscount = DiaoShiCharscount + 1
ElseIf DiaoShiItem Like "[‧.]" Then '過片
If DiaoShiCharscount = 0 Then
'Stop 'check '過片不應出現在調式的一開始!
MsgBox "過片不應出現在調式的一開始!請檢查原 excel 工作表是否有誤!" & vbCr & vbCr & vbCr & _
"〈" & 詞牌 & "〉調式「" & DiaoShi & "」"
Exit For
End If
p.Range.Characters(DiaoShiCharscount).InsertAfter " "
DiaoShiCharscount = DiaoShiCharscount + 2
ElseIf DiaoShiItem = "." Then '?未知,先不處理
If DiaoShiCharscount = 0 Then
'Stop
MsgBox "小數點「.」不應出現在調式的一開始!請檢查原 excel 工作表是否有誤!" & _
"〈" & 詞牌 & "〉調式「" & DiaoShi & "」"
Exit For
End If
Else
Stop 'check
End If
Next j
nextRecord:
DiaoShiCharscount = 0
詞牌rst.MoveNext
p.Range.Paragraphs.Add
If Not p.Next Is Nothing Then
Set p = p.Next
End If
p.Range.Text = DiaoShi & Chr(13) '插入調式欄位值 要注意多插入一個段落,i 不能增動,否則會影響詞牌段落的判斷
Set p = p.Previous '因為插入了 chr(13) 分段符號,故須再回到前一段
addParagraphCount = addParagraphCount + 1 '加了1個段落
p.Range.Font.Name = "Calibri"
If Not 詞牌rst.EOF Then
p.Range.Paragraphs.Add
Set p = p.Range.Paragraphs.Add
addParagraphCount = addParagraphCount + 2 '加了2個段落
If Not p.Next Is Nothing Then
Set p = p.Next
End If
p.Range.Text = 詞文 & Chr(13) '要注意多插入一個段落,i 不能增動,否則會影響詞牌段落的判斷
Set p = p.Previous '因為插入了 chr(13) 分段符號,故須再回到前一段
p.Range.Select '檢查用
Else
If Not p.Next Is Nothing Then
詞牌rst.Close
GoTo NextParagraph
Else
Exit For
End If
End If
Loop
Else
p.Range.Select
If MsgBox("沒有符合的調式可套用!" & vbCr & vbCr & "是否繼續?", vbExclamation + vbOKCancel) = vbCancel Then Exit For
詞牌rst.Close
GoTo NextParagraph
End If
End If
NextParagraph:
Next
ExitExe:
If myRngFlag = False Then '若都沒有吻合的,則還原文件原樣
Do Until UndoTimes = 0
UndoTimes = UndoTimes - 1
.Undo
Loop
End If
End With
de = Timer
MsgBox "完成!" & vbCr & vbCr & "費時" & VBA.Left(de - ds, 5) & "秒!", vbInformation
CommandBars("Navigation").Visible = True
d.ActiveWindow.DocumentMap = True
If 詞牌rst.State = adStateOpen Then 詞牌rst.Close
db.Close
Set 詞牌rst = Nothing: Set db = Nothing
Exit Sub
ErrH:
Select Case Err.Number
Case Else
MsgBox Err.Number & Err.Description, vbCritical
Resume 'Next
'Stop
End Select
End Sub