How to write and read Cyrillic properly from file? - c++

I have the following code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
string rus = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦШЩЪЫЬЭЮЯ";
string lat = "abvgděëžzijklmnoprstufhcčšŝŭeûâABVGDĚËŽZIJKLMNOPRSTUFHCČŠŜŬEÛÂ";
ifstream gdata("data.txt");
if(!gdata){
gdata.open("data.txt");
}
string temp;
while(gdata){gdata >> temp;}
gdata.close();
ofstream sdata("data.txt", ios::out | ios::trunc);
for(unsigned int i = 0; i < temp.length(); i++){
int index = rus.find(temp[i]);
if(index == -1){sdata << temp[i];}
else{sdata << lat[index];}
}
sdata.close();
return 0;
}
I would like to read Russian Cyrillic from a file. Then, program would find the index of each character in the string rus, and if it finds the character, then it finds the corresponding letter within lat string. This letter would then be written to the file.
Unfortunately, when I type something into the file and then run the program, I get weird output such as #>A8 with random squares (not visible here for some reason). How can I make my program read the Cyrillic properly?
I have already looked at over 10 questions here about similar subjects, but considering I'm very much a beginner in C++, nevermind encoding, I didn't understand the answers in the slightest, mainly as no example was provided that I could understand.
Also, even if most characters are latin and there is just one Cyrillic in the text, the entire text becomes malformed into random letters like #>A8

Related

how to select a sentence from a text with c++

i have a question, how to separate one file .txt into 3 files based on the keywords using c++. so each keyword has it's own sentence. so each new sub file contains keywords with their respective sentences. i have tried to show it on console, and it works, but i can't separate the text by it's keywords.
so i have a file. every sentence in this file
so I have a file. There are many sentences here. So, every sentence starts with the words error, warning, and information. how to separate each sentence starting with each of these words, and make them 3 separate files
can you help me please?
i've tried this code, and its failed.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
ifstream myFile;
string data,output,buffer, line;
bool isData = false;
myFile.open("try.txt");
while(getline(myFile, buffer)){
if (buffer == "Error"){
getline(myFile,buffer);
cout<< buffer <<endl;
}
}
cin.get();
return 0;
}

How to read a specific amount of characters

I can get the characters from console with this code:
Displays 2 characters each time in a new line
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
char ch[3] = "";
ifstream file("example.txt");
while (file.read(ch, sizeof(ch)-1))
{
cout << ch << endl;
}
return 0;
}
My problem is, if the set of characters be odd it doesn't displays the last character in the text file!
my text file contains this:
abcdefg
it doesn't displays the letter g in the console
its displaying this:
ab
cd
ef
I wanna display like this:
ab
cd
ef
g
I wanna use this to read 1000 characters at a time for a large file so i don't wanna read character by character, It takes a lot of time, but it has a problem if u can fix it or have a better suggestion, share it with me
The following piece of code should work:
while (file) {
file.read(ch, sizeof(ch) - 1);
int number_read_chars = file.gcount();
// print chars here ...
}
By moving the read call into the loop, you'll be able to handle the last call, where too few characters are available. The gcount method will provide you with the information how many characters were actually read by the last unformatted input operation, e.g. read.
Please note, when reading less than sizeof(ch) chars, you manually have to insert a NUL character at the position returned by gcount, if you intend to use the buffer as a C string, as those are null terminated:
ch[file.gcount()] = '\0';

Generate random .txt file, 10 rows, 10 columns. Filled with randomised: "*","#","#". Then replace random character with 'P'

I'm beginner in C++. Learning mostly from YouTube courses. I was doing the task when I came across the problem which stops me from finishing. I would like to ask for help with the part of code.
#include <iostream>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <sstream>
#include <ostream>
using namespace std;
int main()
{
srand(time(0));
ofstream file;
cout<<"TASK"<<"\n";
file.open("TASK.txt", fstream::in | fstream::out | fstream::trunc );
if(file.good() == true)
{
cout<<"TRUE"<<"\n";
char ch[] = {'#','#','*'}; // Array of three chars.
for(int i=0; i<10; i++)
{
for(int j=0; j<10; j++)
{
file<<ch[rand()%3]; //Random character
}
file<<endl;
}
file.seekp(rand()%120);
file.put('P');
file.close();
}
else cout<<"FALSE"<<"\n";
return 0;
}
What I've done:
Opened a file and created array for 3 characters from task description.
Created 2 for loops which write and format the file data.
Found out by using file.seekp(0,file.end) that the amount of characters in file equals 120.
Used knowledge of the amount of characters to file.seekp(rand()%120) which sets position in output sequence to random place.
Used file.put('P') to place character in that place.
Closed file.
What I don't know:
How to get rid of (or do something else to) these 20+ characters to change only these: '#', '#', '*'.
To visualise the problem:
OUTPUT: when it works as intended.
##*#*###*#
##*##*###*
##**##*###
###*###P**
****####*#
####*#####
**######*#
#*#*####*#
*####*##*#
##*#######
When it doesn't work as intended:
#######*#*
##*##*###*
######*#*#P
*###**###*
##*#*#*#**
**####*#**
#####*#***
###**####*
##*######*
####*#*###
If I wasn't clear enough I can try to explain more.
Solution (thanks to rustyx)
int r_number = 0;
for(int i=0; i<=120; i++)
{
int r_number2 = rand()%120;
if((r_number2%12)>=10)
{
r_number2 = rand()%120;
}
else r_number=r_number2;
}
Thank you.
The problem is that there are CR, LF characters (\r\n) at the end of each line, which shouldn't be touched. But you generate a random number between 0 and 119, which can hit those and damage the file.
I can think of 2 possible solutions:
loop and get a new random number if the remainder of dividing by 12 is >= 10 (you see why?)
get a random number between 0 and 99 and pad it for CR, LF: x += (x/10)*2
I don't know how VC++ handles file position in text mode, it might treat CR, LF as a single position. In that case adjust the padding logic from 12 to 11.

I have made a program in C++ to separate words from a line by spacebar and display those words as an array. What's wrong in my code?

Please help me to find a bug in this program.It separates a line into words by spacebar. And display as a list.
If the first char of a word is in lower case, it is converted to uppercase.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char line[30]="Hi there buddy",List[10][20];
unsigned int i=0,List_pos=0,no;
int first=0,last;
while(i!=sizeof(line)+1)
{
if(line[i]==' ' or i==sizeof(line))
{
last=i;
no=0;
for(int j=first;j<last;++j)
{
if(no==0)
List[List_pos][no]=toupper(line[j]);
else
List[List_pos][no]=line[j];
++no;
}
++List_pos;
first=last+1;
}
++i;
}
for(unsigned int a=0;a<List_pos;++a)
cout<<"\nList["<<a+1<<"]="<<List[a];
return 0;
}
Expected Output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Actual Output:
List[1]=Hi
List[2]=ThereiXŚm
List[3]=Buddy
I suggest you use a string, as you already included it. And 'List is not really necessary in this situation. Try making a single for loop where you separate your line into words, in my opinion when you work with arrays you should use for loops. In your for loop, as you go through the line, you could just add a if statement which determines whether you're at the end of a word or not. I think the problem in your code is the multiple loops but I am not sure of it.
I provide you a code which works. Just adapt it to your display requirements and you will be fine
#include <iostream>
#include <string>
using namespace std;
int main()
{
string line = "Hi there buddy";
for (int i = 0; i < line.size(); i++) {
if (line[i] == ' ') {
line[i + 1] = toupper(line[i+1]);
cout<<'\n';
} else {
cout<<line[i];
}
}
return 0;
} ```
Challenged by the comment from PaulMcKenzie, I implemented a C++ solution with 3 statements:
Define a std::string, with the words to work on
Define a std::regex that finds words only. Whitespaces and other delimiters are ignored
Use the std::transform to transform the input string into output lines
std::transform has 4 parameters.
With what the transformation should begin. In this case, we use the std::sregex_token_iterator. This will look for the regex (so, for the word) and return the first word. That's the begin.
With what the transformation should end. We use the empty std::sregex_token_iterator. That means: Do until all matches (all words) have been read.
The destination. For this we will use the std::ostream_iterator. This will send all transformed results (what the lambda returns) to the given output stream (in our case std::cout). And it will add a delimiter, here a newline ("\n").
The transormation function. Implemented as lambda. Here we get the word from the std::sregex_token_iterator and transform it into a new word according to what we want. So, a word with a capitalized first letter. We add a little bit text for the output line as wished by the OP.
Please check:
#include <string>
#include <iostream>
#include <regex>
#include <iterator>
int main()
{
// 1. This is the string to convert
std::string line("Hi there buddy");
// 2. We want to search for complete words
std::regex word("(\\w+)");
// 3. Transform the input string to output lines
std::transform(
std::sregex_token_iterator(line.begin(), line.end(), word, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[i = 1](std::string w) mutable {
return std::string("List[") + std::to_string(i++) + "]=" + static_cast<char>(::toupper(w[0])) + &w[1];
}
);
return 0;
}
This will give us the following output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Please get a feeling for the capabilities of C++
Found a solution for your next problem (when the user inputs a sentence only the first word it displayed). When you input a "space", the cin just thinks you are done. You need to use the getLine() to get the whole sentence.
getline(cin, line);
Instead of
cin>>line;

replace and write to file c++

I want write code to find words in a file and replace words.
I open file, next I find word. I have a problem with replace words.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string contain_of_file,a="car";
string::size_type position;
ifstream NewFile;
NewFile.open("plik1.txt");
while(NewFile.good())
{
getline(NewFile, contain_of_file);
position=contain_of_file.find("Zuzia");
if(position!=string::npos)
{
NewFile<<contain_of_file.replace(position,5, a );
}
}
NewFile.close();
cin.get();
return 0;
}
How can I improve my code?
lose the using namespace std;
don't declare the variables before needed;
I think the English word you were looking for was content -- but I am not an English-native speaker;
getline already returns NewFile.good() in boolean context;
No need to close NewFile explicitly;
I would change the casing on the NewFile variable;
I don't think you can write to an ifstream, and you ought to manage how you are going to replace the contents of the file...
My version would be like:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdio>
int main() {
std::rename("plik1.txt", "plik1.txt~");
std::ifstream old_file("plik1.txt~");
std::ofstream new_file("plik1.txt");
for( std::string contents_of_file; std::getline(old_file, contents_of_file); ) {
std::string::size_type position = contents_of_file.find("Zuzia");
if( position != std::string::npos )
contents_of_file = contents_of_file.replace(position, 5, "car");
new_file << contents_of_file << '\n';
}
return 0;
}
There are at least two issues with your code:
1. Overwriting text in a file.
2. Writing to an ifstream (the i is for input, not output).
The File object
Imagine a file as many little boxes that contain characters. The boxes are glued front to back in an endless line.
You can take letters out of boxes and put into other boxes, but since they are glued, you can't put new boxes between existing boxes.
Replacing Text
You can replace text in a file as long as the replacement text is the same length as the original text. If the text is too long, you overwrite existing text. If the replacement text is shorter, you have residual text in the file. Not good in either method.
To replace (overwrite) the text, open the file as fstream and use the ios::in and ios::out modes.
Input versus Output
The common technique for replacing text is to open the original file for *i*nput and a new file as *o*utput.
Copy the existing data, up to your target text, to the new file.
Copy the replacement text to the new file.
Copy any remaining text to the new file.
Close all files.