I'm using a CStdioFile and trying to leave a number of white spaces before writing a CString.
I tried CStdioFile.Seek(iNumOfSpaces, CStdioFile::current) the i write the string.
the problem is that when I open the file in Notepad++ it writes NUL instead of the white spaces.
How to write the white spaces to be viewed as white not NUL?
Thanks in advance
You misunderstood what CFile::Seek() method does. It moves the file pointer to a specified position, absolutely or relatively. It does not add/modify the content of the file.
Instead you should use CString::Format() method that supports padding. Here is an example that shows how to use it:
CString s;
s.Format(_T("|%-10s|"), _T("Data")); // left-align
s.Format(_T("|%10s|"), _T("Data")); // right-align
The result string is going to look like:
|Data |
| Data|
Here is an example that shows how to implement dynamic (variable length) padding:
CString s;
int n = 10;
s.Format(_T("|%-*s|"), n, _T("Data")); // left-align
s.Format(_T("|%*s|"), n, _T("Data")); // right-align
1.
CString hh="i7mjmhb";
CString h(' ',31);
hh=h+hh;
2.
CString hh=L"i7mjmhb";
CString h(L' ',31);
hh=h+hh;
With files it's bad not to know forward is it ascii or unicode stuff
Related
I'm doing the project that convert the python code to C++, for better performance. That python project name is Adcvanced EAST, for now, I got the input data for nms function, in .csv file like this:
"[ 5.9358170e-04 5.2773970e-01 5.0061589e-01 -1.3098677e+00
-2.7747922e+00 1.5079222e+00 -3.4586751e+00]","[ 3.8175487e-05 6.3440394e-01 7.0218205e-01 -1.5393494e+00
-5.1545496e+00 4.2795391e+00 -3.4941311e+00]","[ 4.6003381e-05 5.9677261e-01 6.6983813e-01 -1.6515008e+00
-5.1606908e+00 5.2009044e+00 -3.0518508e+00]","[ 5.5172237e-05 5.8421570e-01 5.9929764e-01 -1.8425952e+00
-5.2444854e+00 4.5013981e+00 -2.7876694e+00]","[ 5.2929961e-05 5.4777789e-01 6.4851379e-01 -1.3151239e+00
-5.1559062e+00 5.2229333e+00 -2.4008298e+00]","[ 8.0250458e-05 6.1284608e-01 6.1014801e-01 -1.8556541e+00
-5.0002270e+00 5.2796564e+00 -2.2154367e+00]","[ 8.1256607e-05 6.1321974e-01 5.9887391e-01 -2.2241254e+00
-4.7920742e+00 5.4237065e+00 -2.2534993e+00]
one unit is 7 numbers, but a '\n' after first four numbers,
I wanna read this csv file into my C++ project,
so that I can do the math work in C++, make it more fast.
using namespace std;
void read_csv(const string &filename)
{
//File pointer
fstream fin;
//open an existing file
fin.open(filename, ios::in);
vector<vector<vector<double>>> predict;
string line;
while (getline(fin, line))
{
std::istringstream sin(line);
vector<double> preds;
double pred;
while (getline(sin, pred, ']'))
{
preds.push_back(preds);
}
}
}
For now...my code emmmmmm not working ofc,
I'm totally have no idea with this...
please help me with read the csv data into my code.
thanks
Unfortunately parsing strings (and consequently files) is very tedious in C++.
I highly recommend using a library, ideally a header-only one, like this one.
If you insist on writing it yourself, maybe you can draw some inspiration from this StackOverflow question on how to parse general CSV files in C++.
You could look at getdelim(',', fin, line),
But the other issue will be those quotes, unless you /know/ the file is always formatted exactly this way, it becomes difficult.
One hack I have used in the past that is NOT PERFECT, if the first character is a quote, then the last character before the comma must also be a matching quote, and not escaped.
If it is not a quote then getdelim() some more, but the auto-alloc feature of getdelim means you must use another buffer. In C++ I end up with a vector of all the pieces of getdelim results that then need to be concatenated to make the final string:
std::vector<char*> gotLine;
gotLine.push_back(malloc(2));
*gotLine.back() = fgetch();
gotLine.back()[1] = 0;
bool gotquote = *gotLine.back() == '"'; // perhaps different classes of quote
if (*gotLine.back() != ',')
for(;;)
{
char* gotSub= nullptr;
gotSub=getdelim(',');
gotLine.push_back(gotSub);
if (!gotquote) break;
auto subLen = strlen(gotSub);
if (subLen>1 && *(gotSub-1)=='"') // again different classes of quote
if (sublen==2 || *(gotSub-2)!='\\') // needs to be a while loop
break;
}
Then just concatenate all these string segments back together.
Note that getdelim supports null bytes. If you expect null bytes in the content, and not represented by the character sequences \000 or \# you need to store the actual length returned by getdelim, and use memcpy to concatenate them.
Oh, and if you allow utf-8 extended quotes it gets very messy!
The case this doesn't cover is a string that ends \\" or \\\\". Ideally you need to while count the number of leading backslashes, and accept the quote if the count is even.
Note that this leave the issue of unescaping the quoted content, i.e. converting any \" into ", and \\ into \, etc. Also discarding the enclosing quotes.
In the end a library may be easier if you need to deal with completely arbitrary content. But if the content is "known" you can live without.
I want to concatenate three string in C++.
I have a vector std::vector<std::string> my_list where the filenames are stored. I want to add the directory and filename extension for each of the filenames in order to read binary the information from the file, so i do it like that:
for (int i = 0; i < my_list.size(); i++) {
std::string tmp = prefix + my_list[i] + suffix;
std::ifstream file(tmp.c_str(), std::ifstream::binary);
}
where prefix ist std::string prefix = "directory/" and suffix ist std::string suffix = ".foo".
And it works in Windows. However it doesn't work in Linux.
Suffix overwrites "tmp"-string. It looks like foo/y_file_timestamp instead of out/my_file_timestamp.foo.
What should I do to prevent this overwriting?
The bug is not in the code you showed us.
The problem is that your strings have unexpected characters in them, specifically carriage returns ('\r') that cause the caret to return to the beginning of the line during output of your concatenated string to the terminal window.
Presumably this is a problem caused by careless parsing of input data with Windows-style line endings. You should normalise your data and be sure to strip all line-ending variants during parsing.
Always be sure to check the contents of your strings at the character-level when encountering a problem with string operations.
Thank you #BarryTheHatchet. I forgot to mention that vector my_list was filled this way:
std::string LIST_WITH_DATA = "data/list.scp"
const char* my_data = LIST_WITH_DATA.c_str();
std::ifstream my_file(my_data);
std::string my_line;
while (std::getline(my_file, my_line)) {
my_list.push_back(my_line);
}
data/list.scp looks like:
file1/00001-a
file2/00001-b
file3/00001-c
file4/00001-d
std::getline was my problem.
The solution I found here: Getting std :: ifstream to handle LF, CR, and CRLF?
I have a small program, that is meant to copy a small phrase from a file, but it appears that I am either misinformed as to how seekg() works, or there is a problem in my code preventing the function from working as expected.
The text file contains:
//Intro
previouslyNoted=false
The code is meant to copy the word "false" into a string
std::fstream stats("text.txt", std::ios::out | std::ios::in);
//String that will hold the contents of the file
std::string statsStr = "";
//Integer to hold the index of the phrase we want to extract
int index = 0;
//COPY CONTENTS OF FILE TO STRING
while (!stats.eof())
{
static std::string tempString;
stats >> tempString;
statsStr += tempString + " ";
}
//FIND AND COPY PHRASE
index = statsStr.find("previouslyNoted="); //index is equal to 8
//Place the get pointer where "false" is expected to be
stats.seekg(index + strlen("previouslyNoted=")); //get pointer is placed at 24th index
//Copy phrase
stats >> previouslyNotedStr;
//Output phrase
std::cout << previouslyNotedStr << std::endl;
But for whatever reason, the program outputs:
=false
What I expected to happen:
I believe that I placed the get pointer at the 24th index of the file, which is where the phrase "false" begins. Then the program would've inputted from that index onward until a space character would have been met, or the end of the file would have been met.
What actually happened:
For whatever reason, the get pointer started an index before expected. And I'm not sure as to why. An explanation as to what is going wrong/what I'm doing wrong would be much appreciated.
Also, I do understand that I could simply make previouslyNotedStr a substring of statsStr, starting from where I wish, and I've already tried that with success. I'm really just experimenting here.
The VisualC++ tag means you are on windows. On Windows the end of line takes two characters (\r\n). When you read the file in a string at a time, this end-of-line sequence is treated as a delimiter and you replace it with a single space character.
Therefore after you read the file you statsStr does not match the contents of the file. Every where there is a new line in the file you have replaced two characters with one. Hence when you use seekg to position yourself in the file based on numbers you got from the statsStr string, you end up in the wrong place.
Even if you get the new line handling correct, you will still encounter problems if the file contains two or more consecutive white space characters, because these will be collapsed into a single space character by your read loop.
You are reading the file word by word. There are better methods:
while (getline(stats, statsSTr)
{
// An entire line is read into statsStr.
std::string::size_type posn = statsStr.find("previouslyNoted=");
// ...
}
By reading entire text lines into a string, there is no need to reposition the file.
Also, there is a white-space issue when reading by word. This will affect where you think the text is in the file. For example, white space is skipped, and there is no telling how many spaces, newlines or tabs were skipped.
By the way, don't even think about replacing the text in the same file. Replacement of text only works if the replacement text has the same length as the original text in the file. Write to a new file instead.
Edit 1:
A better method is to declare your key strings as array. This helps with positioning pointers within a string:
static const char key_text[] = "previouslyNoted=";
while (getline(stats, statsStr))
{
std::string::size_type key_position = statsStr.find(key_text);
std::string::size_type value_position = key_position + sizeof(key_text) - 1; // for the nul terminator.
// value_position points to the character after the '='.
// ...
}
You may want to save programming type by making your data file conform to an existing format, such as INI or XML, and using appropriate libraries to parse them.
void CcalculatorDlg::OnBnClickedButton1()
{
CString grabData = _T("");
m_display.GetLine(0,grabData.GetBuffer(10),10);
grabData += _T("1");
m_display.SetWindowTextW(grabData.GetBuffer());
grabData.ReleaseBuffer();
}
I am trying to make a basic calculator application using MFC, and I am having some trouble with the number inputs.
Above is the code for when the "1" button is pressed. I want it to read in what's already being displayed in the display control, and then add a 1 onto the end of it like real calculators do. However I just can't get it to work.
Basically the first button press it works and changes the blank display (edit control) to a 1. But then successive presses don't continue to add 1's, and I cannot figure out why.
I think the problem in your code is that you tried to modify the string (concatenating _T("1")) after calling GetBuffer() but before calling ReleaseBuffer(). Moreover, you have unbalanced GetBuffer()/ReleaseBuffer() calls.
Assuming that m_display is a CEdit instance, you can try code like this (worked for me):
void CcalculatorDlg::OnBnClickedButton1()
{
// Get current text from edit control
// (assume a single-line edit control)
CString grabData;
m_display.GetWindowText(grabData);
// Concatenate "1"
grabData += L'1';
// Update edit control text
m_display.SetWindowText(grabData);
}
If you have a multi-line edit control and you want to grab the first (top-most) line using CEdit::GetLine(), you can use code like this (note that according to MSDN documentation, EM_GETLINE doesn't NUL-terminate the copied line, so you have to explicitly specify line length to ReleaseBuffer()):
//
// Read first line from edit control
//
CString grabData;
static const int kMaxBufferLength = 80;
wchar_t* buffer = grabData.GetBuffer(kMaxBufferLength + 1);
// Note '+ 1' for NUL string terminator (it seems that EM_GETLINE, which is
// wrapped by CEdit::GetLine(), doesn't NUL-terminate the returned string).
const int grabDataLength = m_display.GetLine(0, buffer, kMaxBufferLength);
grabData.ReleaseBuffer(grabDataLength);
// *After* calling ReleaseBuffer(), you can modify the string, e.g.:
grabData += L'1'; // concatenate "1"
I am reading a text file which contains a word with a punctuation mark on it and I would like to read this word into a string without the punctuation marks.
For example, a word may be " Hello, "
I would like the string to get " Hello " (without the comma). How can I do that in C++ using ifstream libraries only.
Can I use the ignore function to ignore the last character?
Thank you in advance.
Try ifstream::get(Ch* p, streamsize n, Ch term).
An example:
char buffer[64];
std::cin.get(buffer, 64, ',');
// will read up to 64 characters until a ',' is found
// For the string "Hello," it would stream in "Hello"
If you need to be more robust than simply a comma, you'll need to post-process the string. The steps might be:
Read the stream into a string
Use string::find_first_of() to help "chunk" the words
Return the word as appropriate.
If I've misunderstood your question, please feel free to elaborate!
If you only want to ignore , then you can use getline.
const int MAX_LEN = 128;
ifstream file("data.txt");
char buffer[MAX_LEN];
while(file.getline(buffer,MAX_LEN,','))
{
cout<<buffer;
}
EDIT: This uses std::string and does away with MAX_LEN
ifstream file("data.txt");
string string_buffer;
while(getline(file,string_buffer,','))
{
cout<<string_buffer;
}
One way would be to use the Boost String Algorithms library. There are several "replace" functions that can be used to replace (or remove) specific characters or strings in strings.
You can also use the Boost Tokenizer library for splitting the string into words after you have removed the punctuation marks.