Программа Word VBA читает символ Emoji (4 байта) как «12» - PullRequest
17 голосов
/ 19 мая 2019

Я создал документ только с одним «большим пальцем вверх» Emoji (кодовая точка Unicode U + 1F44D), который я вставил через стандарт Windows + ; ярлык:

Windows + ; shortcut for Emojis

Но я не могу получить его фактическую кодовую точку с VBA .

Я получаюэти значения (отладка):

text = 12
length = 2
arrBytes = { 49, 0, 50, 0 }

со следующей процедурой Sub:

Sub test()
    Dim text As String
    Dim length As Integer
    Dim arrBytes() As Byte
    text = ActiveDocument.Range.Characters(1).text
    length = Len(ActiveDocument.Range.Characters(1).text)
    arrBytes = ActiveDocument.Range.Characters(1).text
End Sub

Но если бы я вставил тот же Emoji через меню Вставка > Symbol > Шрифт "Segoe UI Emoji"> U + 1F44D (большой палец вверх), та же процедура Sub получает ожидаемые значения (в отладке; ?? не являются "реальными" символами,это суррогатные кодовые точки , которые по отдельности ничего не значат):

text = ??
length = 2
arrBytes = { 61, 216, 77, 220 }

(для информации код декодирует два символа в &#x1F44D)

Как определить действительный символ, если Emoji вставлен с использованием Windows + ; ? (просьба пользователей выбрать обходной путь выше не является частьюмойвопрос)

ADDENDUM 26 мая : решение @Florent B. работает на всех моих 3 компьютерах (ActiveDocument.Content.InsertXML ActiveDocument.Content.XML).Перезагрузка XML может оказать влияние на программы VBA, например, он перенумеровывает изображение «Идентификаторы формы», но это уже другая история.

ADDENDUM 22 мая : для символа, добавленного с Windows + ; , правильное значение (4 байта {61, 216, 77, 220}) я могу найти только в свойстве XML объекта Range объекта документа, но для этого требуется, чтобы япроанализировать весь XML и определить, какие символы XML соответствуют каким позициям объектов Range, к сожалению, я считаю, что это требует больших знаний или предположений.Вот часть XML, где я вижу 4 байта (<w:t>??</w:t>, где ?? соответствует 4 байтам):

  <?xml version="1.0" standalone="yes"?>
  <?mso-application progid="Word.Document"?>
  <w:wordDocument ...>
    ... (around 23.000 characters)
    <w:body>
      <wx:sect>
        <w:p wsp:rsidR="002703DB" wsp:rsidRDefault="003926FB">
          <w:r>
            <w:rPr>
              <w:rFonts w:ascii="Segoe UI Emoji" w:h-ansi="Segoe UI Emoji"/>
              <wx:font wx:val="Segoe UI Emoji"/>
            </w:rPr>
            <w:t>??</w:t>
          </w:r>
        </w:p>
        <w:sectPr wsp:rsidR="002703DB" wsp:rsidSect="002849CD"><w:pgSz w:w="11906"
                w:h="16838"/><w:pgMar w:top="1417" w:right="1417" w:bottom="1417"
                w:left="1417" w:header="708" w:footer="708" w:gutter="0"/><w:cols
                w:space="708"/><w:docGrid w:line-pitch="360"/></w:sectPr>
      </wx:sect>
    </w:body>
  </w:wordDocument>

XML равен почти , когдаЯ вставляю Emoji как символ, есть еще 2 «rFonts»:

    <w:body>
      <wx:sect>
        <w:p wsp:rsidR="00CD420D" wsp:rsidRDefault="00CD420D">
          <w:r>
            <w:rPr>
              <w:rFonts w:ascii="Segoe UI Emoji" w:fareast="Segoe UI Emoji"
                    w:h-ansi="Segoe UI Emoji" w:cs="Segoe UI Emoji"/>
              <wx:font wx:val="Segoe UI Emoji"/>
            </w:rPr>
            <w:t>??</w:t>
          </w:r>
        </w:p>
        <w:sectPr wsp:rsidR="00CD420D" wsp:rsidSect="002849CD"><w:pgSz w:w="11906"
                w:h="16838"/><w:pgMar w:top="1417" w:right="1417" w:bottom="1417"
                w:left="1417" w:header="708" w:footer="708" w:gutter="0"/><w:cols
                w:space="708"/><w:docGrid w:line-pitch="360"/></w:sectPr>
      </wx:sect>
    </w:body>
  </w:wordDocument>

PS: компьютеры / программное обеспечение, где я мог воспроизвести проблему:

  • Компьютер 1: MSWord Office 365 1904 (16.0.11601.20174) 32 бита, Windows 10 Professional 10.0.17763 x64
  • Компьютер 2: MS Word Office 365 1904 (16.0.11601.20184) 64 бита, Windows 10 Professional 1809 17763.503 x64
  • Компьютер 3: MS Word Office 365 ProPlus 1808 (16.0.10730.20334) 64 бита, Windows 10 Enterprise 10.0.17763 x64

Ответы [ 2 ]

2 голосов
/ 25 мая 2019

Надеюсь, это поможет: основываясь на комментариях @ SandraRossi, приведенных выше, кажется, что вклад от панели эмодзи неправильно переведен в суррогатную кодовую точку. Если вы сохраните документ, содержащий оба символа (один из панели Emoji, а другой из меню, как вы описали) в виде документа XML, вы заметите разницу:

Emoji Ввод:

<w:r w:rsidR="003814F5">
  <w:rPr>
    <mc:AlternateContent>
      <mc:Choice Requires="w16se">
        <w:rFonts w:ascii="Segoe UI Emoji" w:hAnsi="Segoe UI Emoji"/>
      </mc:Choice>
      <mc:Fallback>
        <w:rFonts w:hint="eastAsia"/>
      </mc:Fallback>
    </mc:AlternateContent>
  </w:rPr>
  <mc:AlternateContent>
    <mc:Choice Requires="w16se">
      <w16se:symEx w16se:font="@SimHei" w16se:char="1F44D"/>
    </mc:Choice>
    <mc:Fallback>
      <w:t>?</w:t>
    </mc:Fallback>
  </mc:AlternateContent>
</w:r>

Ввод меню (символа):

<w:r w:rsidR="003814F5">
  <w:rPr>
    <w:rFonts w:ascii="Segoe UI Emoji" w:hAnsi="Segoe UI Emoji"/>
  </w:rPr>
  <w:t xml:space="preserve"> is not ?</w:t>
</w:r>

Строка <w16se:symEx w16se:font="@SimHei" w16se:char="1F44D"/> является ключевым отличием здесь. Нормальный (Menu -> Insert Symobol) эмодзи используется как запасной вариант.

Кажется, только Word имеет проблему. Я попробовал тот же ввод с панели эмодзи в Excel (и PowerPoint), и я получил правильные значения в отладке ??, которая преобразуется в кодовую точку Unicode U+1F44D как в Excel, так и при копировании обратно в Word.

0 голосов
/ 10 июня 2019

Вот мои последние убеждения и выводы.

Вероятно, это ошибка в MS Word VBA, основанная на тестах, выполненных AAA в Excel, Powerpoint и Word.Некоторые люди не имеют этой ошибки (см. Комментарии).

Объекты VBA дают недопустимое значение для emoji, но свойство XML является правильным.XML слишком сложный, чтобы его можно было легко проанализировать, поэтому Флорент Б. нашел в комментариях самый простой обходной путь, заключающийся в «воссоздании документа из себя»:

ActiveDocument.Content.InsertXML ActiveDocument.Content.XML

К сожалению, в моем личномВ этом случае он может иметь некоторые побочные эффекты, например, нумерация идентификаторов фигур.

Итак, я расширил приведенный выше код для исправления только символов эмодзи в исходном документе, остальное осталось без изменений, путем:

  • копирование XML в новый документ
  • с последующим синтаксическим анализом каждого символа, длина текста которого> 1, в новом документе (т. Е. Вне базовой многоязычной плоскости Unicode, содержащейEmojis и многие другие символы тоже),
  • также анализирует исходный документ (при условии, что символы должны быть в том же порядке, что и в новом документе, и их длина текста одинакова),
  • копированиеэти символы из нового документа обратно в исходный документ,
  • , закрывающий новый документ.

Хорошо, макросы работают дольше, но я не смог найти лучшего решения.

Вот мой упрощенный код (вы можете быть удивлены бесполезной коллекцией объектов Range, где каждый Range - это один символьный объект,на самом деле я не предоставляю исходный код для функции Split_Into_Ranges, которая намного больше, но быстрее, но она работает и хорошо демонстрирует решение в подпункте correct_emojis):

Sub test()

    Dim text As String
    Dim length As Integer
    Dim arrBytes() As Byte

    Dim zranges As Collection
    Set zranges = Split_Into_Ranges(ActiveDocument)

    Call correct_emojis(zranges) ' <=== here the important algorithm

    text = ActiveDocument.Range.Characters(1).text
    length = Len(ActiveDocument.Range.Characters(1).text)
    arrBytes = ActiveDocument.Range.Characters(1).text

End Sub

Function Split_Into_Ranges(ioDocument As Document) As Collection

    Dim zranges As Collection
    Set zranges = New Collection
    For i = 1 To ioDocument.Characters.Count
        zranges.Add ioDocument.Characters(i)
    Next
    Set Split_Into_Ranges = zranges

End Function

Sub correct_emojis(zranges As Collection)

    Dim current_emoji_zranges As Collection
    Dim temp_zranges As Collection
    Dim temp_emoji_zranges As Collection
    Dim doc_current As Document
    Dim doc_temp As Document
    Dim arrBytes() As Byte

    Set doc_current_zranges = get_emoji_zranges(zranges)
    If doc_current_zranges.Count = 0 Then
        Exit Sub
    End If

    Set doc_current = ActiveDocument
    Set doc_temp = Documents.Add()
    Call doc_temp.Content.InsertXML(doc_current.Content.XML)
    Set temp_zranges = Split_Into_Ranges(doc_temp)

    Set current_emoji_zranges = get_emoji_zranges(zranges)
    Set temp_emoji_zranges = get_emoji_zranges(temp_zranges)

    For i = 1 To current_emoji_zranges.Count
        If 0 = 1 Then
            arrBytes = current_emoji_zranges(i).Characters(1).text
            arrBytes = temp_emoji_zranges(i).Characters(1).text
        End If
        current_emoji_zranges(i).Characters(1).text = temp_emoji_zranges(i).Characters(1).text
    Next

    Call doc_temp.Close(False)

End Sub

Function get_emoji_zranges(zranges As Collection) As Collection

    Dim emoji_zranges As Collection

    Set emoji_zranges = New Collection
    For i = 1 To zranges.Count
        If Len(zranges(i).text) > zranges(i).Characters.Count Then
            For j = 1 To zranges(i).Characters.Count
                If Len(zranges(i).Characters(j).text) > 1 Then
                    emoji_zranges.Add (zranges(i))
                End If
            Next
        End If
    Next

    Set get_emoji_zranges = emoji_zranges

End Function
...