← Back to list

[Microsoft Word] Find and Replace for Unicode Ranges ≥ U+10000

Microsoft Word has “Find and Replace” function that can not only change text to other text but also change style, font or various…

Turgenev · 2024-01-04 05:48 · 0 claps · 2.9 min read
#microsoft-word #unicode #ms-word #cjk #vba
Open on Medium ↗
Wiki topics: 👗 · Fashion

[Microsoft Word] Find and Replace for Unicode Ranges ≥ U+10000

Microsoft Word has “Find and Replace” function that can not only change text to other text but also change style, font or various properties of text.

It also has some regular-expression-like specification. This article describe how to specify a unicode range outside BMP (Basic Multilingual Plane), above U+10000, which is quite undocumented.

A Prerequisite: How to Apply Find and Replace to All Text by Word VBA

We typically want to replace all text including that in header/footer or textbox, and the Find and Replace dialog does this. However, doing this is a bit difficult in Word VBA. This is also quite undocumented.

This site gives comprehensive explanation to this problem, providing a perfect source code to Find and Replace all text.

Also, you may want to use Application.UndoRecord to treat all the Find and Replace as one action (which determines the behavior of Ctrl+Z).

You may have to combine this with what I present here.

Grapheme Cluster

Firstly, Find and Replace in MS Word seems to recognize characters only according to “grapheme cluster” in Unicode. In short, a grapheme cluster is a (set of) character(s) that can’t be separated by input cursor. For example, R͆ is a ligature of separate two characters, “R”(U+0052) and “͆”(U+0346), but the text cursor can’t usually go between the two characters and R͆ is apparently treated as a single character.

Therefore, when MS Word is ordered to replace “R” with “X”, it won’t change “R͆” to “X͆”. We must specify the whole “R͆” to replace “R͆”.

It is not that the character(s) “R͆” itself must be present at the specification. For example, a specification [A-Z]͆ can be used to change the font of all characters A͆, B͆, …, Z͆.

Surrogate pairs in UTF-16

MS Word seems to use UTF-16 encoding, so a Unicode character outside BMP (above U+10000) is internally a kind of “ligature” of two characters from 0xD800–0xD8FF (high surrogate) and 0xDC00–0xDCFF (low surrogate).

Therefore, we can’t specify a Unicode range with characters above U+10000 as usual.

For example, [𐀀-𐀏] (10000–1000F) appears to MS Word like [{D800}{DC00}-{D800}{DC0F}] , where {XXXX} (of course there is no such syntax in actual MS Word) indicates a “separate” character. Then word detects{DC00}-{D800} as invalid unicode range, because the beginning character of the range is larger than the ending character (just like [Z-A] is invalid).

So, to solve this problem, we need some expression like [{D800}{DC00}-{DC0F}] . You can also use range expression in both high and low surrogates: [{D800}-{D801}][{DC00}-{DFFF}] specifies all 2048 characters between U+10000 — U+107FF.

Note that you can only specify unicode characters in “a rectangle drawn on a 1024x1024 character table indexed by high surrogates and low surrogates” at once. Since Find and Replace has no “OR” expression, you may have to run Find and Replace three times at most in order to specify some unicode range (for example, U+10001—U+107FE) (this is a bit like a small mathematical problem).

Also, since they are not authentic characters, surrogate characters are difficult to input in the dialog. Using Alt+X in Word can produce surrogate characters (typically rendered as a rectangle) and they did work in my testing, but I recommend using Word VBA.

Code Example

This sample Word VBA code change the color of all characters between U+10000 — U+107FF to red, using Application.UndoRecord.

Sub Find_Replace_All_Text()
  Set objUndo = Application.UndoRecord
  objUndo.StartCustomRecord ("Replace All With VBA")
  'Fix the skipped blank Header/Footer problem.
  lngValidate = ActiveDocument.Sections(1).Headers(1).Range.StoryType
  'Iterate through all story types in the current document.
  Dim rngStory As Range
  For Each rngStory In ActiveDocument.StoryRanges
    'Iterate through all linked stories.
    Do
      Change_Red rngStory
      On Error Resume Next
      Select Case rngStory.StoryType
        Case 6, 7, 8, 9, 10, 11
          If rngStory.ShapeRange.Count > 0 Then
            For Each oShp In rngStory.ShapeRange
              If oShp.TextFrame.HasText Then
                Change_Red oShp.TextFrame.TextRange
              End If
            Next
          End If
        Case Else
          'Do Nothing
      End Select
      On Error GoTo 0
      'Get next linked story (if any)
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
  objUndo.EndCustomRecord
End Sub

Sub Change_Red(myRange As Range)
    Dim UniRange As String
    UniRange = "[" & ChrW(&HD800) & "-" & ChrW(&HD801) & "][" & ChrW(&HDC00) & "-" & ChrW(&HDFFF) & "]"

    myRange.Find.ClearFormatting
    myRange.Find.Replacement.ClearFormatting
    myRange.Find.Replacement.Font.Color = wdColorRed
    With myRange.Find
        .text = UniRange
        .Replacement.text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchCase = False
        .MatchWholeWord = False
        .MatchByte = False
        .MatchAllWordForms = False
        .MatchSoundsLike = False
        .MatchFuzzy = False
        .MatchWildcards = True
        .Execute Replace:=wdReplaceAll
    End With
End Sub

메타데이터
post_id
79ab2b32e138
slug
microsoft-word-find-and-replace-for-unicode-ranges-u-10000-79ab2b32e138
url
https://medium.com/@turgenev.e9g/microsoft-word-find-and-replace-for-unicode-ranges-u-10000-79ab2b32e138
canonical_url
https://medium.com/@turgenev.e9g/microsoft-word-find-and-replace-for-unicode-ranges-u-10000-79ab2b32e138
author_url
https://medium.com/@turgenev.e9g
status
ok
fetched_at
2026-06-16 19:09:56