Сопоставить дополнительные символы Юникода с BMP (если возможно)
Я столкнулся с проблемой, заключающейся в том, что мой синтаксический анализатор XML (VTD-XML) не может обрабатывать дополнительные символы Юникода (пожалуйста, исправьте, если я уже здесь не прав). Кажется, парсер использует только младшие 16 бит таких символов.
Я не могу переключиться на другой парсер в проекте, которым я занят. Я анализирую тезисы Medline ( https://www.ncbi.nlm.nih.gov/pubmed), и кажется, что за последний год были добавлены документы, содержащие дополнительные символы (например, https://www.ncbi.nlm.nih.gov/pubmed/?term=26855708, раздел "Концы результатов").
В качестве быстрого и грязного исправления я просто удалил бы все символы выше 0xFFFF из документов. Очевидно, что это разрушит некоторые выражения в текстах документов, и поэтому я не очень доволен этим решением.
Поскольку я не могу изменить синтаксический анализатор, мне было интересно, существует ли какая-либо возможность сопоставить дополнительные символы с символами в BMP, которые могут иметь глиф с похожим внешним видом, если таковой существует.
Конечно, я приветствую любую другую идею. Было бы даже неплохо заменить дополнительные символы каким-то заполнителем, а затем вернуть исходный символ обратно, но это кажется подверженным ошибкам. Лучшие идеи?
Изменить: Вот несколько - надеюсь - минимальный пример того, как эта проблема возникает с VTD-XML:
@Test
public void parseUnicodeBeyondBMP() throws NavException, FileNotFoundException, IOException, EncodingException, EOFException, EntityException, ParseException {
// character codpoint 0x10400
String unicode = "<supplementary>\uD801\uDC00</supplementary>";
byte[] unicodeBytes = unicode.getBytes();
assertEquals(unicode, new String(unicodeBytes, "UTF-8"));
VTDGen vg = new VTDGen();
vg.setDoc(unicodeBytes);
vg.parse(false);
VTDNav vn = vg.getNav();
long fragment = vn.getContentFragment();
int offset = (int) fragment;
int length = (int) (fragment >> 32);
String originalBytePortion = new String(Arrays.copyOfRange(unicodeBytes, offset, offset+length));
String vtdString = vn.toRawString(offset, length);
// this actually succeeds
assertEquals("\uD801\uDC00", originalBytePortion);
// this fails ;-( the returned character is Ѐ, codepoint 0x400, thus the high surrogate is missing
assertEquals("\uD801\uDC00", vtdString);
}