I have documents written in old Kazakh font (Kazakhstan), using win98. Nowadays we are using Times New Roman, but this font shows strange unicode characters. I can use substitution (Ctrl + H) to change all symbols to Times New Roman encoding, but we have 42 (84 in both cases) letters.
For example I have all symbols from old font in first line, and all symbols from new font at the second line in the same order.
Can someone write an example script that will read this two lines char by char, making something like a dictionary in Java then do a global substitution.
Update
Thanks Roman Plischke!
I wrote a macro that recursively applies to all *.doc files in some folder.
Sub Substitution()
'
' Substitution of the chars from font Times/Kazakh
' to Times New Roman
' Chars to substitute are 176-255 bytes, 73 and 105 byte
Dim sTab As String
sTab = "£ª½¥¡¯Ž¼º¾´¢¿žÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"
Selection.Find.Font.Shadow = False
Selection.Find.Replacement.Font.Shadow = False
For i = 1 To Len(sTab)
With Selection.Find
.Text = ChrW(i + 175)
.Replacement.Text = Mid(sTab, i, 1)
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Text = Selection.Find.Text
Next i
Selection.Find.Execute Replace:=wdReplaceAll
With Selection.Find
.Text = ChrW(105)
.Replacement.Text = "³"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Text = Selection.Find.Text
With Selection.Find
.Text = ChrW(73)
.Replacement.Text = "²"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Text = Selection.Find.Text
' kazakh language
Selection.WholeStory
Selection.LanguageID = WdLanguageID.wdKazakh
Application.CheckLanguage = False
Selection.Collapse Direction:=wdCollapseStart
End Sub
' Function that Call Substitution() for all documents
' in folder vDirectory
Sub LoopDirectory()
Dim vDirectory As String
Dim oDoc As Document
vDirectory = "E:\soft\Dedushka\not\"
vFile = Dir(vDirectory & "*.doc")
Do While vFile <> ""
Set oDoc = Documents.Open(FileName:=vDirectory & vFile)
Debug.Print ActiveDocument.Name + " Started"
Call Zamena
Debug.Print ActiveDocument.Name + " Finish"
oDoc.Close SaveChanges:=True
vFile = Dir
Loop
End Sub
I used for similar conversions this subroutine. The "heart" of code is a definition of string sTab. This string contains all charactesr for code 127 and above. Fill this string by new characters one by one.
If you have a code table of the old Kazakh coding, it is very simple: type in the VBA editor all characters starting 127 char. VBA editor works in Unicode, so this works.
If you have not a code table, you have to get an old code of each character (try select this character and press Alt+X) and write it manually in the string at right position.
In both cases, for unused (or unusually) character you may fill a space or other character.
The rest of code replaces each character with code above 127 for new character from sTab.
Sub Convert()
Dim sTab As String
Dim sKod As String
Dim i As Long
Dim ch As String
'new chars 127-255:
'note: for each character above 127 fill in this table unicode character
sTab = "ÄÃãÉ¥ÖÜá¹ÈäèÆæéŸÏí“”ëEóeôöoúÌìü†°Ê£§•¶ß®©™ê¨‡gIlÎ__îK__³Ll¼¾ÅåNnѬVñÒ_«»… òÕOõO–—“”‘’÷_OÀàØ‹›øRrŠ‚„šŒœÁÍŽžUÓÔuÙÚùÛûUuÝýk¯£¿G¡"
'clear all shadow - we use this attrib as flag for changed characters
Selection.Find.ClearFormatting
Selection.Find.Font.Shadow = True
Selection.Find.replacement.ClearFormatting
Selection.Find.replacement.Font.Shadow = False
With Selection.Find
.Text = ""
.replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
'changing characters by codetable
Selection.Find.Font.Shadow = False
Selection.Find.replacement.Font.Shadow = True
For i = 1 To Len(sTab)
With Selection.Find
ch = Chr(126 + i)
If ch = "^" Then ch = "^^"
.Text = ch
ch = Mid(sTab, i, 1)
If ch = "^" Then ch = "^^"
.replacement.Text = ch
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.Find.Text = Selection.Find.Text
Next i
'clear shadows
Selection.Find.Font.Shadow = True
Selection.Find.replacement.Font.Shadow = False
With Selection.Find
.Text = ""
.replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
' kazakh language
Selection.WholeStory
Selection.LanguageID = WdLanguageID.wdKazakh
Application.CheckLanguage = False
Selection.Collapse Direction:=wdCollapseStart
End Sub
Related
I am using Microsoft Visual Basic on Word. I want to limit the find and replace function to operate only on certain pages of the document. How do I do it?
As of now, it will execute it the whole document which is not preferred.
Sub X_entity()
'
' Replaces lower and greater than symbols to html entity
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = ">"
.Replacement.Text = ">"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
With Selection.Find
.Text = "<"
.Replacement.Text = "<"
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
Instead of using Selection (which is poor practice anyway), you should point to the range of each page in turn, using Find/Replace on the designated range only. For example:
Sub ProcessPages()
Application.ScreenUpdating = False
Dim i As Long, ArrPgs()
' Define the pages to process
ArrPgs = Array("7", "4", "3", "2")
For i = 0 To UBound(ArrPgs)
' Process the defined pages
With ActiveDocument.Range.GoTo(What:=wdGoToPage, Name:=ArrPgs(i)).GoTo(What:=wdGoToBookmark, Name:="\page").Find
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWildcards = False
.Text = ">"
.Replacement.Text = ">"
.Execute Replace:=wdReplaceAll
.Text = "<"
.Replacement.Text = "<"
.Execute Replace:=wdReplaceAll
End With
Next i
Application.ScreenUpdating = True
End Sub
With the above code, the pages are processed in reverse order in case the Find/Replace messes with the pagination.
I am using the following code to bold parts of a text string, in this case where the word 'Fish' is in brackets after the word 'Oil':
Sub ReplaceAndFormat16()
Dim sConst1 As String, sReplaceMent As String
Dim rRange As Range, rFormat As Range
sConst1 = "Fish"
sReplaceMent = "Oil (" & sConst1 & ")"
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "Oil (Fish)"
.Replacement.Text = sReplaceMent
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute Replace:=wdReplaceOne
If .Found Then
Set rRange = Selection.Range
Set rFormat = ActiveDocument.Range(rRange.Start + 5, rRange.Start + 5 + VBA.Len(sConst1))
rFormat.Font.Bold = True
End If
End With
End Sub
This code works perfectly, but only bolds the first instance, and my documents may have up to four instances of this phrase that need to be formatted bold.
How do I amend the code so it carries on and bolds all instances in the document? I am very new to VBA, so apologies if this seems like a stupid question.
Change the line
.Execute Replace:=wdReplaceOne
to
.execute Replace:=wdReplaceAll
Edit
OK the above was a stupid response. The code below does the right thing
Sub ReplaceAndFormat16()
Const myFindStr As String = "Oil (Fish)"
Dim myFindRange As Word.Range
Set myFindRange = ActiveDocument.StoryRanges(wdMainTextStory)
Do
With myFindRange.Find
.ClearFormatting
.Text = myFindStr
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If .Found Then
With myFindRange
.MoveStartUntil cset:="fF"
.MoveEndUntil cset:="hH", Count:=wdBackward
.Font.Bold = True
.Collapse Direction:=wdCollapseEnd
End With
Else
Exit Sub
End If
End With
Loop
End Sub
I have been working on a code that finds and replaces words to make them italics. However, I cannot figure out how to make this more efficient using an array.
Currently my code is this were I just keep copying and pasting the with loop:
Sub ItalicsText()
'
' ItalicsText Macro
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.Italic = True
With Selection.Find
.Text = "Lord of the Rings"
.Replacement.Text = "Lord of the Rings"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.EscapeKey
End Sub
However, I would like to make it so that I could have an array like:
vFindText = Array("Lord of the Rings", "blah", "blah")
I want to do this because I have hundreds of phrases to check and want to make it faster for me to code.
Untested:
Sub AllTexts()
Dim vFindText, v
vFindText = Array("Lord of the Rings", "blah", "blah")
For Each v in vFindText
ItalicsText v
Next v
End Sub
Sub ItalicsText(findWhat)
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Font.Italic = True
With Selection.Find
.Text = findWhat
.Replacement.Text = findWhat
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
Selection.EscapeKey
End Sub
in this code, I want to do the following:
If the word is finished with a letter M Replace with letter N.
If the word ends with a letter N, Replace with letter M.
I do not know well using the IF - Then statement.
Any help would be greatly appreciated.
Sub find_end()
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "[nm]>"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.MatchWildcards = True
Selection.Find.Execute
With Selection
If Selection.Find.Found = n Then
Selection.TypeText Text:=m
ElseIf Selection.Find.Found = m Then
Selection.TypeText Text:=n
End If
End Sub
I modified the code found at: Repeating Microsoft Word VBA until no search results found
and it will spin thru a document and replace the last letter (if it's an 'm' or 'n') of each word. NOTE there is a 'loop check in that code that you may want to remove if it's possible you may find over 2000 m or n's.
Option Explicit
' The following code adapted from: https://stackoverflow.com/questions/13465709/repeating-microsoft-word-vba-until-no-search-results-found
Sub SearchFN()
Dim iCount As Integer
Dim lStart As Long
'Always start at the top of the document
Selection.HomeKey Unit:=wdStory
'find a footnote to kick it off
With Selection.Find
.ClearFormatting
.Text = "[nm]>"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchKashida = False
.MatchDiacritics = False
.MatchAlefHamza = False
.MatchControl = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchFuzzy = False
.MatchWildcards = True
.Execute
End With
'Jump back to the start of the document.
Selection.HomeKey Unit:=wdStory
'If we find one then we can set off a loop to keep checking
'I always put a counter in to avoid endless loops for one reason or another
Do While Selection.Find.Found = True And iCount < 2000
iCount = iCount + 1
Selection.Find.Execute
'On the last loop you'll not find a result so check here
If Selection.Find.Found Then
' Exit if we start back at the beginning
If Selection.Start < lStart Then
Exit Do
End If
'Reset the find parameters
With Selection.Find
.ClearFormatting
.Text = "[nm]>"
If Selection.Text = "m" Then
Debug.Print "found 'm' at position: " & Selection.Start
Selection.Text = "n"
ElseIf Selection.Text = "n" Then
Debug.Print "found 'n' at position: " & Selection.Start
Selection.Text = "m"
End If
lStart = Selection.Start
' .Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchKashida = False
.MatchDiacritics = False
.MatchAlefHamza = False
.MatchControl = False
.MatchByte = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchFuzzy = False
.MatchWildcards = True
End With
End If
Loop
End Sub
My intent is to create a very basic macro to find a series of words and highlight them. Unfortunately, I do not know how to do multiple words in one step. For example, the following code works:
Sub Macro1()
'
' Macro1 Macro
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Highlight = True
With Selection.Find
.Text = "MJ:"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
However, if I add in another .Text = line, then the MJ: is ignored. Any ideas?
If you are only looking for a few words simply doing multiple find and replaces within the same macro will accomplish what you want. For example, the following will highlight in yellow all occurrences of "target1" and "target2"
Sub HighlightTargets()
' --------CODE TO HIGHLIGHT TARGET 1-------------------
Options.DefaultHighlightColorIndex = wdYellow
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Highlight = True
With Selection.Find
.Text = "target1"
.Replacement.Text = "target1"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
' --------CODE TO HIGHLIGHT TARGET 1-------------------
Options.DefaultHighlightColorIndex = wdYellow
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Highlight = True
With Selection.Find
.Text = "target2"
.Replacement.Text = "target2"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
Alternatively the following code will let you add all the terms to highlight in one line which may be easier to work with.
Sub HighlightTargets2()
Dim range As range
Dim i As Long
Dim TargetList
TargetList = Array("target1", "target2", "target3") ' put list of terms to find here
For i = 0 To UBound(TargetList)
Set range = ActiveDocument.range
With range.Find
.Text = TargetList(i)
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
Do While .Execute(Forward:=True) = True
range.HighlightColorIndex = wdYellow
Loop
End With
Next
End Sub
I had done the following modification. Perhaps not as elegant as the array. But I was thinking along the lines of a user simply pasting a list of values into a field.
Sub HighlightKeyword(SearchWord As String)
'
' HighlightKeyword Macro
'
Options.DefaultHighlightColorIndex = wdYellow
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
Selection.Find.Replacement.Highlight = True
With Selection.Find
.Text = SearchWord
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = True
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
Sub HighlightKeywordList()
'
' HighlightKeywordList
'
'
Dim HighlightList As String
Dim WordList As Variant
HighlightList = "Lorem Ipsum,amit,Finibus,Bonorum,et Malorum,Vestibulum,Vivamus,Integer"
WordList = Split(HighlightList, ",")
For i = 0 To UBound(WordList)
HighlightKeyword (WordList(i))
Next i
End Sub