Ошибка ошибки сегментации при замене юникода на пробел в строке C ++ - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь заменить Unicode-символ 'NO-BREAK SPACE' (U + 00C2) т.е. Â на пробел "" в строке str при выполнении через в некоторых случаях это дает мне ошибка сегментации . Может ли кто-нибудь подсказать мне, как это недопустимый доступ к памяти.
Я делаю это правильно?
Есть ли другой способ сделать это?

string str = "transaction applies: Â Â Â Â Â Â Â Â Â {79}";
void cleanup(string& str)
    {   
        string unicode = "\u00C2";
        size_t pos = str.find(unicode);
        while(str.find(unicode, pos)!=string::npos && pos != str.length())
        {   
            pos = str.find(unicode, pos);
            str.replace(pos, unicode.length(), " " ); //unicode replace by a space  
            // this above line is giving segmentation fault
            pos = pos + unicode.length();
        }
        return;
    }

Выход:

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Существует путаница между символом Unicode и его представлением utf-8. NO-BREAK SPACE - это действительно символ Юникода U + 00A0, а его представление utf-8 - "\xc2\xa0" И Â - это ПИСЬМО ЛАТИНСКОГО КАПИТАЛА С CIRCUMFLEX, или символ Юникода U + 00C2, и его представление в Юникоде "\xc3\x82".

Это означает, что ваша начальная строка не содержит пробела. Если ваш набор символов редактора - Latin1 или windows cp1252, он будет содержать повторения «\ xc2 \ x20» (т. Е. Латинские символы «В» и пробел), а если это utf8, он будет содержать повторы «\ xc3 \ x82 \ x20». "(т. е. utf8 в коде 'и'). Затем, когда вы ищете вхождение «\ u00A0», вы фактически ищете вхождения «\ xc2 \ xa0», которого нет в исходной строке. Ошибка сегментации вызвана тем, что pos является std::string::npos: str.find(unicode, pos) вызывает неопределенное поведение.

Что делать: выбери свою сторону. Поскольку вы используете узкие строки, вы должны решить, какую кодировку вы используете. Если вы используете utf8 (распространенный в мире Linux), то символ NO-BREAK SPACE представляет собой строку длиной 2 символа: { 0xc2, 0xa0 }. И эта строка:

string unicode = "\u00A0";

точно такой же, как этот:

string unicode = "\xc2\xa0";

и прежде всего контролируйте, что у вас есть действующий пункт перед его использованием:

   ...
   size_t pos = str.find(unicode);
   if (pos == string::npos) return;
   ...
0 голосов
/ 05 июля 2018

Достаточно просто сделать это.

std::string str("transaction applies: Â Â Â Â Â Â Â Â Â {79}");
std::transform(str.begin(), str.end(), str.begin(), [](char c) -> char {return (c == (char)'\u00C2') ? ' ': c ; });
0 голосов
/ 05 июля 2018

Основная проблема заключается в том, что вы заменяете все символы пробелами, а затем ищете следующий специальный символ. После попытки заменить несуществующий символ - pos = string::npos.

Вот простая модификация вашего цикла while, чтобы он работал (полезно cout для трассировки включено):

void cleanup(string& str) {
  string unicode = "\u00C2"; // \u00C2 is Â
  size_t pos = str.find(unicode);
  while(pos != string::npos) {
    cout << "str: " << str << "\tpos: " << pos << endl;
    str.replace(pos, unicode.length(), " ");
    pos = pos + unicode.length();
    pos = str.find(unicode, pos);
  }
}

Вы можете (и, вероятно, должны) изменить это для цикла for-each над символами вашей строки или цикла do-while для упрощения кода. Но причина, по которой он не работает, заключается в том, что, как указано выше, вы попытались заменить pos, которого не было.

Не предполагая, что это лучшая программа, но возможное преобразование для цикла for-each, так что вы можете увидеть пример в C ++ 11:

#include <locale>
#include <codecvt>
#include <iostream>
#include <string>

using namespace std;

// Using u16string because of unicode characters
void cleanup(u16string& str) {
  for(auto& c : str)
    if(c == u'\u00C2')
      c = u' ';
}

int main() {
  u16string str = u"transaction applies: \u00C2 \u00C2 \u00C2 \u00C2 \u00C2 \u00C2 \u00C2 \u00C2 \u00C2 {79}";
  cleanup(str);

  wstring_convert<codecvt_utf8<char16_t>, char16_t> convert;
  cout << convert.to_bytes(str) << endl;
}
...