0 / 0 / 0
Регистрация: 15.05.2016
Сообщений: 24
1

Русский язык в Linux, регистр

09.09.2016, 01:30. Показов 6695. Ответов 15
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте, пытаюсь запустить код, работавший в Visual Studio на Debian, IDE Codeblocks. Возникла проблема с переводом русских слов в нижний регистр (строка 34). Латиницу переводит, но русский не принимает. Помогите, пожалуйста, заранее спасибо.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <cctype>
#include <algorithm>
#include <time.h>
#include <regex>
using namespace std;
 
struct Word
{
    std::string word = "";
    int wordfreq = 0;
};
 
int main(int argc, _TCHAR* argv[])
{
    
    setlocale(LC_ALL, "Russian");
    
    cin >> NewFile;
 
    map <string, int> words; // контейнер для входного текста
    ifstream in;
    in.open(NewFile);// файл с входным текстом
    string word;
    int wCount = 0; // счетчик слов во входном тексте
 
    while (in >> word) // удаляем не важные символы из текста
    {
        setlocale(LC_ALL, "");
        std::transform(word.begin(), word.end(), word.begin(), tolower);// перевод в нижний регистр
        for (int i = 0; i<word.size(); i++)
        {
            if (word[i] == '.' || word[i] == ',' || word[i] == '(' || word[i] == ')' || word[i] == '[' || word[i] == ']' || word[i] == '!' || word[i] == '?' ||
                word[i] == '"' || word[i] == ';' || word[i] == ':' || word[i] == '#' || word[i] == '$' || word[i] == '%' || word[i] == '^' || word[i] == '&' ||
                word[i] == '*' || word[i] == '*' || word[i] == '+' || word[i] == '-' || word[i] == '“' || word[i] == '/' || word[i] == '”' || word[i] == '„' ||
                word[i] == '_' || word[i] == '—' || word[i] == '«' || word[i] == '»' || word[i] == '…' || word[i] == '*' || word[i] == '–') {
                word.erase(word.begin() + i);
                i--;
            }
        }
 
        if (!word.empty() && word != "--")
            words[word]++;
        wCount++;
    }
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
09.09.2016, 01:30
Ответы с готовыми решениями:

Почему Linux понимает русский язык, и как разучить его это делать?
Здравствуйте! Зная, что в Linux принята неравномерная кодировка UTF-8, я удивлялся, как считай...

Xcode , С++ и русский язык: как вывести в файл русский текст без сбитой кодировки?
Как сделать так, чтобы после некоторых манипуляций в файл выводился русский текст без сбитой...

Английский язык для окна ввода пароля, русский язык для самой системы
собственно, сабж. у меня пароль на английском языке, при включении компьютера по умолчанию стоит...

Русский язык
Всем добрый день! Как исправить проблему того, что в консоле вместо русского языка отображаются...

15
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
09.09.2016, 01:33 2
особенное внимание обратите на наличие локали
http://www.cplusplus.com/reference/locale/tolower/
0
0 / 0 / 0
Регистрация: 15.05.2016
Сообщений: 24
09.09.2016, 01:56  [ТС] 3
hoggy, Сделал по примеру, русский текст не тронут, но теперь английский поплыл. В верхний регистр переводит.
0
Модератор
Эксперт С++
13554 / 10795 / 6428
Регистрация: 18.12.2011
Сообщений: 28,813
09.09.2016, 07:31 4
Ну так меняйте локаль на время перевода английского текста обратно.
0
0 / 0 / 0
Регистрация: 15.05.2016
Сообщений: 24
09.09.2016, 13:12  [ТС] 5
В любом случае регистр русских слов не смог поменять, подскажите, пожалуйста, как именно мой код нужно изменить. С удовольствием выслушаю все возможные варианты.
0
2783 / 1936 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
09.09.2016, 14:54 6
Цитата Сообщение от asdawvwv Посмотреть сообщение
Возникла проблема с переводом русских слов в нижний регистр (строка 34). Латиницу переводит, но русский не принимает.
У пингвинов по умолчанию utf-8, tolower в него не умеет и уметь не будет даже после плясок с бубном вокруг локалей (потому что под обнобайтовые кодировки). Самый простой выход - переделать файл в utf-16/utf-32 и читать в wstring. Плюс, кинуть в начало программы std::setlocale(LC_ALL,"Что ни будь из выдачи locale -a, только не C/POSIX");.
1
0 / 0 / 0
Регистрация: 15.05.2016
Сообщений: 24
09.09.2016, 15:39  [ТС] 7
Renji, Перегнал в utf16 входной файл. Перелопатил программу под wstring, вылетает с ошибкой invalyde byte sequence in file. Локаль воткнул в начале utf8. Кроме нее только с и посикс.
0
2783 / 1936 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
09.09.2016, 16:16 8
Цитата Сообщение от asdawvwv Посмотреть сообщение
Renji, Перегнал в utf16 входной файл. Перелопатил программу под wstring, вылетает с ошибкой invalyde byte sequence in file.
Хм, поэкспериментировал у себя, ерунда какая-то. Вроде бы пишу std::wifstream, но оно все равно расценивает файл как utf-8. При этом читая из него только английский текст, несмотря на вроде бы верно выставленную локаль. Ну, в общем, файл в utf-32 то я открыл, но к стыду своему, только через костыль.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include<fstream>
using namespace std;
 
int main()
{
    setlocale(LC_ALL,"C.UTF-8");
    std::ifstream stream("test.txt");
    //получаем размер файла
    stream.seekg(0,std::ios_base::end);
    size_t size=stream.tellg();
    stream.seekg(0);
 
    //и низкоуровневым чтением его, чтоб точно ничего не сбойнуло
    std::wstring str(size/sizeof(wchar_t),' ');
    stream.read((char*)str.data(),size);
 
    //выводим что прочитали
    wcout<<str;
    return 0;
}
0
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
09.09.2016, 16:18 9
Цитата Сообщение от asdawvwv Посмотреть сообщение
invalyde byte sequence in file
Задайте локаль для wifstream.
C++
1
in.imbue(std::locale(""));
1
2783 / 1936 / 570
Регистрация: 05.06.2014
Сообщений: 5,600
09.09.2016, 16:19 10
Цитата Сообщение от Nosey Посмотреть сообщение
Задайте локаль для wifstream.
Хм, а с imbue на utf-8 файле действительно работает.
0
0 / 0 / 0
Регистрация: 15.05.2016
Сообщений: 24
09.09.2016, 17:09  [ТС] 11
Renji, Ваш код возврашает ноль на любом файле( в консоль ничего не выводит. С wifstream ругается на строку 16.
УПД. В строке 16 поменял чар на wchar_t. Segmentation fault выдает. Файл утф8
0
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
09.09.2016, 17:10 12
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

Цитата Сообщение от Renji Посмотреть сообщение
Хм, а с imbue на utf-8 файле действительно работает.
Все потому что std::setlocale - это сишная локаль, она затрагивает гору свободных функций, а вот на стримы не влияет.
Если желаете общую плюсовую локаль выставить, то std::local::global готов к работе, ну либо *.imbue(..).
0
923 / 639 / 198
Регистрация: 08.09.2013
Сообщений: 1,693
09.09.2016, 20:20 13
Цитата Сообщение от asdawvwv Посмотреть сообщение
В любом случае регистр русских слов не смог поменять, подскажите, пожалуйста, как именно мой код нужно изменить. С удовольствием выслушаю все возможные варианты.
Например, функцией из glib
C++
1
g_utf8_strdown (word.c_str(), -1)
Если известно, что файл в utf-8, то локаль имеет значение, если вы денежные единицы или форматы даты будете менять в зависимости от пользовательских настроек.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
09.09.2016, 22:20 14
Цитата Сообщение от asdawvwv Посмотреть сообщение
Сделал по примеру, русский текст не тронут, но теперь английский поплыл. В верхний регистр переводит.
если вкратце: жизнь - боль и страдание.
с++ не осилил локали.

единственное, что стабильно работает - это английский текст (сишная локаль).
национальные локали либо не работают вообще, либо глючат.

если поприседать вокруг локалей, то можно родить свою собственную,
которая сможет сделать вам хорошо.

но! есть нюанс.
нужно учитывать грандиозный фейл дизайна стандартной библиотеки:
утф-кодировки допускают ненормированный текст:
например в немецком языке сочетания некоторых букв идущих подряд могут обозначать одну.
однако стандартные трейты работают с отдельным символом, а не с полноценным текстом.
что делает невозможной в принципе полноценную работу с утф-кодировкам.
как бы вы не пытались.

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


что касается стандартных средств: максимум, что тут можно сделать:
родить собственную локаль, которая сможет корректно работать только с нормализированным текстом.
то есть, с текстом, в котором национальные символы можно представить одной буквой.

Цитата Сообщение от Nosey Посмотреть сообщение
а вот на стримы не влияет.
влияет.
стримам так же можно посетить локаль.

например, грузить файл в утф8 кодировке.


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#pragma once
 
#ifdef dUSING_PRECOMPILED_HEADER
    #ifndef _STDEXCEPT_
        #error #include <stdexcept> first
    #endif
 
    #ifndef _FSTREAM_
        #error #include <fstream> first
    #endif
 
    #ifndef _CODECVT_
        #error #include <codecvt> first
    #endif
 
    #ifndef _STRING_
        #error #include <string> first
    #endif
#else
    #include <stdexcept>
    #include <fstream>
    #include <codecvt>
    #include <cassert>
    #include <string>
#endif
 
namespace fs{
namespace stream{
 
// ===================================================================================================
// ===================================================================================================
namespace detail
{
    template<class ch> 
    std::basic_ofstream<ch> 
    open__(const std::basic_string<ch>& filename, const int flag, const bool with_BOM)
    {
        std::basic_ofstream<ch> stream_;
 
        #ifdef _MSC_VER
            stream_.open(filename, std::ios::out | flag, _SH_DENYRW);
        #else
            stream.open(filename, std::ios::out | flag);
        #endif
 
        stream_.imbue(get_utf8_locale(with_BOM));
        
        if(!stream_)
            throw std::runtime_error("can`t open file");
 
        return stream_;
    }
 
    inline std::locale get_utf8_locale(const bool with_bom)
    {
        typedef std::codecvt_utf8<wchar_t, 0x10ffff, std::generate_header> 
            bom_codec_t;
        typedef std::codecvt_utf8<wchar_t> 
            no_bom_codec_t;
 
        return with_bom?
            std::locale(std::locale::empty(), new bom_codec_t):
            std::locale(std::locale::empty(), new no_bom_codec_t);
    }
 
    template<class Container, class Value> 
    void append__(Container& cont, Value&& val)
    {
        
        #ifdef _MSC_VER
        __if_exists(Container::emplace_back) 
            { cont.emplace_back( std::forward<Value>(val) );       return; }
 
        __if_exists(Container::push_back)    
            { cont.push_back( std::forward<Value>(val) )   ;       return; }
 
        __if_exists(Container::insert)       
            { cont.insert( cont.end(), std::forward<Value>(val) ); return; }
        #else
        TODO: not implemented...
        #endif
    }
 
}// namespace detail
// ===================================================================================================
// ===================================================================================================
    
// --- пересоздает файл заного
template<class ch> 
std::basic_ofstream<ch>
create(const std::basic_string<ch>& filename, const bool with_BOM)
{
    return detail::open__(filename, std::ios::trunc, with_BOM);
}
// ===================================================================================================
    
// --- открывает для добавления
template<class ch> 
std::basic_ofstream<ch>
append(const std::basic_string<ch>& filename, const bool with_BOM)
{
    return detail::open__(filename, std::ios::app, with_BOM);
}
// ===================================================================================================
    
// --- открывает для чтения    
template<class ch>
std::basic_ifstream<ch>
load(const std::basic_string<ch>& filename, const bool with_BOM)
{
    std::basic_ifstream<ch> stream_;
 
    stream_.open(filename, std::ios::in);
    stream_.imbue(detail::get_utf8_locale(with_BOM));
    
    if(!stream_)
        throw std::runtime_error("can`t open file");
    
    return stream_;
}
// ===================================================================================================
    
// --- хэлпер для загрузки всего файла построчно
template<class ch, class container> 
void load_lines(const std::basic_string<ch>& filename, container& cont, const bool with_BOM)
{
    auto in = load(filename, with_BOM);
    std::basic_string<ch> line;
    while (std::getline(in, line))
        detail::append__(cont, line);
}
    
template<class ch, class container> 
void load_lines(const ch* filename, container& cont, const bool with_BOM)
{
    assert(filename);
    load_lines(std::basic_string<ch>(filename), cont, with_BOM);
}
    
// ===================================================================================================
    
// --- хэлпер для загрузки отдельных слов 
template<class ch, class container> 
void load_words(const std::basic_string<ch>& filename, container& cont, const bool with_BOM)
{
    auto in = load(filename, with_BOM);
    std::basic_string<ch> word;
    while(in >> word)
        detail::append__(cont, word);
}
    
template<class ch, class container> 
void load_words(const ch* filename, container& cont, const bool with_BOM)
{
    assert(filename);
    load_words(std::basic_string<ch>(filename),cont, with_BOM);
}
    
// ===================================================================================================
 
} //namespace stream
} //namespace fs
 
 
#include <iostream>
#include <vector>
#include <set>
 
int main()
{
    setlocale(LC_ALL, "");
    
    std::cout << "Hello, world!\n";
    
    try
    {
        // --- загружаем весь файл построчно в указанный контейнер
        std::vector<std::wstring> mylines;
        fs::stream::load_lines(L"sample-utf8.txt", mylines, true);
    
        // --- загружаем все слова из файла в указанный контейнер
        std::set<std::wstring> mywords;
        fs::stream::load_words(L"sample-utf8.txt", mywords, true);
    }
    catch(const std::exception& e)
    {
        std::cout << e.what()<<std::endl;
    }
}
0
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
09.09.2016, 23:00 15
Цитата Сообщение от hoggy Посмотреть сообщение
если вкратце: жизнь - боль и страдание.
с++ не осилил локали.
Главные слова на деревне.
asdawvwv, также если вкратце, если вы пишите что-то серьезное, то используйте следующее:
Все файлы ресурсов в utf8. Все строки в программулине в u32string(который UCS4, UTF-32), тогда у вас возможно(не все языки, как отметил hoggy) будут работать функции типа tolower..., а потом по нужде, если что, переедите на либу посерьезней.
Прошу заметить, что при кроссплатфрме на wchar не стоит надеяться, только char32(его невозможно сломать реализацией )

Цитата Сообщение от hoggy Посмотреть сообщение
влияет.
стримам так же можно посетить локаль.
например, грузить файл в утф8 кодировке.
Ну-ка ну-ка покажите, как через std::setlocale задать дефолтный codecvt для файловых стримов . Ну а вообще, да, погорячился я с заявлением. std::setlocale задает сишную локаль для глобальных функций, которые уже юзаются фасетами плюсовой локали, но проблема ТС'а в codecvt, который сишной локалью не меняется.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
09.09.2016, 23:17 16
Цитата Сообщение от Nosey Посмотреть сообщение
Ну-ка ну-ка покажите, как через std::setlocale задать дефолтный codecvt для файловых стримов
да дело же не в std::setlocale,
а в том, что стриму можно посетить локаль.
1
09.09.2016, 23:17
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
09.09.2016, 23:17
Помогаю со студенческими работами здесь

Русский язык в C++
Как в C++ консоли подключить русский язык желательной setLoceta(Rus) такой функцией, у меня не...

Русский язык
char szNonColorEmbeddedMsg; int iNonColorEmbeddedMsgLen = 0; for (size_t pos = 0; pos &lt;...

Русский язык
Здравствуйте! Я практикуюсь в создании веб сайтов. Когда я писал сайт и тестировал его на локальном...

русский язык
Вопрос один, как поставить русский язык ODude Ecard . Объясняют ...

Русский Язык!!!
Как в переменную char A; занести Ф только чтоб после отоброжалось не каракули а Ф! и библиотеку!

Русский язык
Собственно, есть проблема. Русский язык вроде работает, но не до конца. То, что написано в коде...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru