Я довольно новичок в c ++, и это одна из моих первых попыток сделать что-то относительно большое / полезное, поэтому, если есть какие-либо явные ошибки, которые не связаны с моим вопросом, конструктивный комментарий приветствуется.
Для некоторых операций, связанных с utf-8, я использую библиотеку C utf8proc .
Проблема
При сборке с последней версией MSVC 15 дляцель отладки, запускающая тестовую программу, использующую этот код (в основном такой же простой, как печать результатов этой функции), выдает ошибку:
Ошибка отладки!
[Некоторая информация о том, какой exe-файл завершился неудачно]
Ошибка проверки во время выполнения # 2 - стек вокруг переменной 'character' был поврежден.
Любой другой компилятор (которыйЯ пробовал) или цель выпуска не выдает эту ошибку, а вместо этого выдает правильный вывод для всего, что я к ней добавляю.
Следует отметить несколько интересных случаев (они были протестированы с помощью gcc):
Во-первых, память codepoint
и character
иногда кажется случайным образом измененной (отсюда и хакерское смягчение: сохранение codepoint
в codepointCopy
).
Во-вторых, character
, однажды закодированная,иногда имеет нечетные завершающие символы (однако я полагаю, что из-за неинициализированной памяти попытки установить память в character
на 0 вручную с помощью memset
не помогли, что-то очевидно отсутствует?), отсюда и хакерский .substr(0, charSize)
, который до сих пор работает нормально.
Код
#include <string>
#include "../include/utf8proc.h"
std::string calculateUnicodeNormalization(const std::string &in, const std::string &mode) {
auto pString = (const utf8proc_uint8_t*) in.c_str();
utf8proc_uint8_t* pOutString;
// These two functions are from c and use malloc to allocate memory, so I free with free()
if (mode == "NFC") {
pOutString = utf8proc_NFC(pString);
} else {
pOutString = utf8proc_NFD(pString);
}
// Converts to a string
std::string retString = std::string((const char*) pOutString);
// Frees what was allocated by malloc
free(pOutString);
return retString;
}
std::string removeAccents(const std::string &in) {
std::string decomposedString = calculateUnicodeNormalization(in, "NFD");
auto pDecomposedString = (const utf8proc_uint8_t*) decomposedString.c_str();
size_t offset = 0;
std::string rebuiltString;
// Iterates through all of the characters, adding to the "offset" each time so the next character can be found
while (true) {
utf8proc_int32_t codepoint;
// This function takes a pointer to a uint8_t array and writes the next unicode character's codepoint into codepoint.
// The -1 means it reads up to 4 bytes (the max length of a utf-8 character).
utf8proc_iterate(pDecomposedString + offset, -1, &codepoint);
// Null terminator, end of string
if (codepoint == 0) {
break;
}
const utf8proc_int32_t codepointCopy = codepoint;
utf8proc_uint8_t character;
// This function takes a codepoint and puts the encoded utf-8 character into "character". It returns the bytes written.
auto charSize = (size_t) utf8proc_encode_char(codepointCopy, &character);
// I had been having some problems with trailing random characters (random unicode), but this seemed to fix it.
// Could that have been related to the error?
std::string realChar = std::string((const char*) &character).substr(0, charSize);
// God knows why this is needed, but the above function call seems to somehow alter codepoint
// Could be to do with the error?
codepoint = codepointCopy;
// Increments offset so the next character now would be read
offset += charSize;
// The actual useful part of the function: gets the category of the codepoint, and if it is Mark, Nonspacing (and not an iota subscript),
// does not add it to the rebuilt string
if ((utf8proc_category(codepoint) == UTF8PROC_CATEGORY_MN) && (codepoint != 0x0345)) {
continue;
}
rebuiltString += realChar;
}
// Returns the composed form of the rebuilt string
return calculateUnicodeNormalization(rebuiltString, "NFC");
}
Вы можете проверить этот код, например, написав функцию main:
#include <iostream>
int main() {
std::cout << removeAccents("ᾤκεον") << std::endl;
}
Иожидая результата "ῳκεον".
Я не совсем уверен, что происходит, и я не вижу каких-либо явных ошибок в памяти (я имею в виду, что в других случаях все работает нормально),но, конечно, из-за моей неопытности я мог что-то упустить.
Любые ответы приветствуются, и, как всегда, если что-то не хватает, пожалуйста, прокомментируйте, чтобы я мог добавить это.