I'm working with visual studio 10, qt addin and opecv library.
What I want to do is to load multiple files using a for-loop:
(I have ui.image_templates_comboBox->currentText() = "cat")
for (int i = 1; i <= 15; i++){
string currentText = ui.image_templates_comboBox->currentText().toStdString();
char name[40];
sprintf(name, "Logos/cat/%s_%d.tif", ¤tText, i);
templ_img [i] = cv::imread( name );
So, I thought this should be working OK, but when I debug it, I hover my mouse above "name" and I notice that there are 4 non-english characters preceding currentText value.
I ask 2 questions:
a) How is it possible to ommit those 4 useless characters? (I typed them as "1234" as this site couldn't display them)
name 0x003a7b04 "Logos/cat/1234cat_1.tif" char [40]
b) It is possible to collapse those 4 lines into 1 using an expression inside imread()?
You cannot use the address of an std::string where a const char* is expected. They are not the same.
sprintf(name, "Logos/cat/%s_%d.tif", currentText.c_str(), i);
You are mixing frameworks to much and you do not understand how sprintf works. Fix it like that:
for (int i = 1; i <= 15; i++){
QString fileName = QString("Logos/cat/%1_%2.tif")
.arg(ui.image_templates_comboBox->currentText())
.arg(i);
templ_img [i] = cv::imread(fileName.toAscii().data()); // or: toLocal8Bit, toLatin1(), toUtf8()
Related
I have an XML file with many values and a working C++ function that can retrieve these values
Two of these values are:
A file path such as: "C:\foo1\foo2" and
A file name: "foo3.txt"
Combining these together, they would become "C:\foo1\foo2\foo3.txt"
However, while trying to set a CString to save a file path, it will give an error because using the character, \, in a string is not allowed due to string notation and its interaction with the \ character.
I am using MFC, and I know WIN32 allows you to create a file path with / instead of \, so: "C:/foo1/foo2/foo3.txt" would work. I tested this in Windows Explorer and it worked.
I would like to collect the file path from XML file, but when it comes in, it will have \ instead of / in its file path, meaning it will not be possible to replace the character (the string coming in will have an error already due to XML not having a problem with the \ character.
How do I safely retrieve the path as a CString, ideally while converting any \ character to a / character.
Now I'm not familiar with the "CString" class you are refering to. Googling the API documentation just has the standard c style char array format commands, so I'm going to assume rightly or wrongly cstring is a char array.
The fact we are going to need to use an object that is not resizable means we either
Need to use the heap, which will be slow, and can leak memory if the memory isn't deleted later
Allow a maximum string length and accept it will be truncated if below this
Heap example (NOTE: I'm not using smart pointers as I assume they don't have access to them, else you'd just std::string and not do this.)
char* escapeString(const char* data, unsigned int length){
//multiplying by 1.5 means this could still truncate,
//but I'm making an educated guess it's not all bad characters.
const int newLen = (length + 1) * 1.5;
char* escaped = new char[newLen + 1];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i++){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index++] = '\\';
}
else if(data[i] == '%'){
escaped[index++] = '%';
}
//else anything else you want to escape
escaped[index++] = data[i];
}
//Make sure a null string is null terminatedescaped
escaped[index] = '\0';
return escaped;
}
int main() {
const char* stringWithBadChars = "I\"m not a %%good \\string";
char* escapedString = escapeString(stringWithBadChars, strlen(stringWithBadChars));
std::cout << escapedString;
delete [] escapedString;
return 0;
}
If we do this on the stack instead it would be a lot faster, but we are limited by the size of the buffer we give, and the size of the buffer in the function. We will return a bool if either fails.
bool escapeString(char* data, unsigned int length){
const int newLen = 1000;
char escaped[1001];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i++){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index++] = '\\';
}
else if(data[i] == '%'){
escaped[index++] = '%';
}
escaped[index++] = data[i];
}
//Make sure a null string is null terminatedescaped
memcpy(data, escaped, index);
escaped[index] = '\0';
return index < length && index < 1000;
}
You could probably get even more efficiency using memmov rather than copy it character by character. Doing it this way you also wouldn't need the second char array.
CString reserves some special characters. Have a look at the Format command as an example. The linked documentation refers you to: Format specification syntax: printf and wprintf functions.
The \ is used as mentioned in the comments to indicate a special character. For example:
\t will insert a tab character.
\" will insert a double quote character.
So when it hits the \ it expects the next character to be one of the special ones. Therefore, when you actually need a backslash, you use \\.
The linked article does explain about % but not the slash. However, tt is exactly the same with % because it too has special meaning. So you would use %% when you want the percent sign.
I'm writing a dialog based MFC application in Visual Studio 2017 in C++. In the dialog I added a list control where the user can change the values of the cells as shown in the picture below:
after he changes the values, I want to check if those values are valid (so if he accidentally pressed the wrong button he will be notified). For this purpose I'm iterating over the different cells of the list and from each cell I extract the text which is written in it into a CString type variable. I want to check that this variable has only 8 characters which are '1' or '0'. The problem with the code I've written is that I get weird values when I try to print the different characters of the CString variable.
The Code for checking the validity of the CString:
void CEditableListControlDlg::OnBnClickedButton4()
{
// TODO: Add your control notification handler code here
// Iterate over the different cells
int bit7Col = 2;
int bit6Col = 3;
int bit5Col = 4;
int bit4Col = 5;
int bit3Col = 6;
int bit2Col = 7;
int bit1Col = 8;
int bit0Col = 9;
for (int i = 0; i < m_EditableList.GetItemCount(); ++i) {
CString bit7 = m_EditableList.GetItemText(i, bit7Col);
CString bit6 = m_EditableList.GetItemText(i, bit6Col);
CString bit5 = m_EditableList.GetItemText(i, bit5Col);
CString bit4 = m_EditableList.GetItemText(i, bit4Col);
CString bit3 = m_EditableList.GetItemText(i, bit3Col);
CString bit2 = m_EditableList.GetItemText(i, bit2Col);
CString bit1 = m_EditableList.GetItemText(i, bit1Col);
CString bit0 = m_EditableList.GetItemText(i, bit0Col);
CString cvalue = bit7 + bit6 + bit5 + bit4 + bit3 + bit1 + bit0;
std::string value((LPCSTR)cvalue);
int length = value.length();
if (length != 7) {
MessageBox("Register Value Is Too Long", "Error");
return;
}
for (int i = 0; i < length; i++) {
if (value[i] != static_cast<char>(0) || value[i] != static_cast<char>(1)) {
char c = value[i];
MessageBox(&c, "value"); // this is where I try to print the value
return;
}
}
}
}
Picture of what get's printed in the message box when I try to print one character of the variable value. I expect to see '1' but instead I see in the message box '1iiiiii`:
I've tried extracting the characters directly from the variable cvalue of type CString like this:
cvalue[i]
and it's length I got by using
strlen(cvalue[i])
but I've got the same result. I've also tried accessing the characters in the variable cvalue of type CString as follows:
cvalue.GetAt(i)
and to get it's length by using:
cvalue.GetLength()
But again, I've got the same results.
Perhaps anyone could advice me how can I check that the characters in the variable cvalue of type CString are '0' or '1'?
Thank you.
You don't need to use std::string to process your strings in this case: CString works fine.
Assuming that your CString cvalue is the string you want to check, you can write a simple loop like this:
// Check cvalue for characters different than '0' and '1'
for (int i = 0; i < cvalue.GetLength(); i++)
{
TCHAR currChar = cvalue.GetAt(i);
if ((currChar != _T('0')) && (currChar != _T('1')))
{
CString message;
message.Format(_T("Invalid character at position %d : %c"), i, currChar);
MessageBox(message, _T("Error"));
}
}
The reason for the apparently weird output in your case is that you are passing a pointer to a character that is not followed by a null-terminator:
// Wrong code
char c = value[i];
MessageBox(&c, "value");
If you don't want to build a CString with a formatted message containing the offending character, like I did in the previous sample code, an alternative could be creating a simple raw char array storing the character you want to output followed by the null-terminator:
// This is an array storing two chars: value[i] followed by '\0' (null)
char s[2] = {value[i], '\0'};
MessageBox(s, "value");
P.S.
I used TCHAR in my code sample instead of char, to make the code more easily portable to Unicode builds. Think of TCHAR as a preprocessor macro that maps to char for ANSI/MBCS builds (which seems your current case), and to wchar_t for Unicode builds.
A Brief Note on Validating User Input
With the above answer, I tried to strictly address your specific problem with CString character validation. But, if you can take a look from a broader perspective, I would definitely consider validating the user input before storing it in the list-view control. For example, you could handle the LVN_ENDLABELEDIT notification from the list-view control, and reject invalid input values.
Or, considering that the only valid values for each bit are 0 and 1, you could let the user select them from a combo-box.
Doing that starting from the MFC's CListCtrl is non-trivial work; so, you may also consider using other open-source controls, like this CGridListCtrlEx control available from CodeProject.
As you write in your last paragraph, "check that the characters in the variable cvalue of type CString are '0' or '1'?".
That's exactly how. '0' is the character 0. But you check for the integer 0, which is equal to the character '\0'. That's the end-of-string character.
I just have a problem with a text that contains Polish diacritical marks (eg. ą, ć, ę, ł, ń, ó, ś, ź, ż) obtained by libcurl from the server. I'm trying to display this text correctly in a Windows C++ console application.
I solved the similar problem with putting to the console screen something like that:
cout << "ąćęźół";
by switching codepage of my source file to: DOS Codepage 852 (Central Europe). Unfortunately it doesn't work out with text passing from libcurl. I think that it works only with the text written directly into the code. So could you tell my some helpful information? I have no idea how to resolve this issue.
Well I've written temporary solution for my problem. It works fine, but I'm not contented of this way:
char* cpl(const char* input)
{
size_t length = strlen(input);
char* output = new char[length+1];
/* Order of the diacretics
Ą ą Ć ć Ę ę
Ł ł Ń ń Ó ó
Ś ś Ź ź Ż ż
*/
const size_t pld_in[] = {
0xA1,0xB1,0xC6,0xE6,0xCA,0xEA,
0xA3,0xB3,0xD1,0xF1,0xD3,0xF3,
0xA6,0xB6,0xAC,0xBC,0xAF,0xBF,
};
const size_t pld_out[] = {
0xA4,0xA5,0x8F,0x86,0xA8,0xA9,
0x9D,0x88,0xE3,0xE4,0xE0,0xA2,
0x97,0x98,0x8D,0xAB,0xBD,0xBE
};
for(size_t i = 0; i < length; i++)
{
bool modified = false;
for(size_t j = 0; j < 18; j++)
{
if(*(input + i) == (*(pld_in + j)) + 0xFFFFFF00)
{
*(output + i) = *(pld_out + j);
modified = true;
break;
}
}
if(!modified)
*(output + i) = *(input + i);
}
*(output + length) = 0x00;
return output;
}
Could you propose better solution of this problem, without characters converting?
The content of the web page returned by libcurl will use the character set of the web page. What's likely happening here is that it's not the character set used by your "codeset", which I presume the MS-Windows term for locale.
libcurl should let you look at the headers of the HTTP response that was received from the server. Look at the Content-Type: header, which will indicate which character set the returned text uses; then look up which codepage uses the same character set.
My code is the following (reduced):
CComVariant* input is an input parameter
CString cstrPath(input ->bstrVal);
const CHAR cInvalidChars[] = {"/*&#^°\"§$[]?´`\';|\0"};
for (unsigned int i = 0; i < strlen(cInvalidChars); i++)
{
cstrPath.Replace(cInvalidChars[i],_T(''));
}
When debugging, value of cstrPath is L"§", value of cInvalidChars[7] is -89 '§'
I have tried to use .Remove() before, but the problem remains the same: when it comes to § or ´, the code table does not seem to match and the char does not get recognized properly and will not be removed. using a TCHAR array for invalidChars results in even different problems ('§' -> 'ᄡ').
The problem seems that I am not using the correct code tables, but everything I tried so far did not result in any success.
I want to successfully replace/delete any occuring '§'..
I also have had a look at several "delete character from string"-Posts but I did not find anything that helped me.
executable code:
CComVariant* pccovaValue = new CComVariant();
pccovaValue->bstrVal = L"§§";
const CHAR cInvalidChars[] = {"§"};
CString cstrPath(pccovaValue->bstrVal);
for (unsigned int i = 0; i < strlen(cInvalidChars); i++)
{
cstrPath.Remove(cInvalidChars[i]);
}
cstrPath = cstrPath;
just break into cstrPath = cstrPath;
According to the comments you are mixing up Unicode and ANSI encodings. It seems that your application is targeting Unicode which is good. You should stop using ANSI altogether.
Declare cInvalidChars like this:
CString cInvalidChars = L"/*&#^°\"§$[]?´`\';|";
The use of the L prefix means that the string literal is a wide character UTF-16 literal.
Then your loop can look like this:
for (int i = 0; i < cInvalidChars.GetLength(); i++)
cstrPath.Remove(cInvalidChars[i]);
I'm new to C++ and I've encountered a problem... I can't seem to create an array of characters from a string using a for loop. For example, in JavaScript you would write something like this:
var arr = [];
function setString(s) {
for(var i = s.length - 1; i >= 0; i--) {
arr.push(s[i]);
}
return arr.join("");
}
setString("Hello World!"); //Returns !dlroW olleH
I know it's a bit complicated, I do have a little bit of background knowledge on how to do it but the syntax of it is still not too familiar to me.
Is there any way that I could do that in c++ using arrays?
Could I join the array elements into one string as I do in JavaScript?
It would be greately appreciated if you could help. Thanks in advance.
If anyone needs more information just tell me and I'll edit the post.
By the way, my code in c++ is really messy at the moment but I have an idea of what I'm doing... What I've tried is this:
function setString(s) {
string arr[s.size() - 1];
for(int i = s.size() - 1; i >= 0; i--) {
arr[i] = s.at(i); //This is where I get stuck at...
//I don't know if I'm doing something wrong or not.
}
}
It would be nice if someone told me what I'm doing wrong or what I need to put or take out of the code. It's a console application compiled in Code::Blocks
std::string has the c_str() method that returns a C style string, which is just an array of characters.
Example:
std::string myString = "Hello, World!";
const char *characters = myString.c_str();
The closest thing to a direct translation of your function:
string setString(string s) {
string arr;
for(int i = s.length() - 1; i >= 0; i--) {
arr.push_back(s[i]);
}
return arr;
}
A std::string is a dynamic array underneath a fairly thin wrapper. There is no need to copy character by character, as it will do it properly for you:
If the character array is null-terminated (that is, the last element is a '\0'):
const char* c = "Hello, world!"; // '\0' is implicit for string literals
std::string s = c; // this will copy the entire string - no need for your loop
If the character array is not null-terminated:
char c[4] = {'a', 'b', 'c', 'd'}; // creates a character array that will not work with cstdlib string functions (e.g. strlen)
std::string s(c, 4); // copies 4 characters from c into s - again, no need for your loop
If you cannot use std::string (e.g. if you are forced to use ANSI C):
const char* c = "Hello, World!";
// assume c2 is already properly allocated to strlen(c) + 1 and initialized to all zeros
strcpy(c2, c);
In your javascript example, you are reversing the string, which can be done easily enough:
std::string s = "Hello, world!";
std::string s1(s.rbegin(), s.rend());
Additionally, you can cut your iterations in half (for both C++ and Javascript) if you fix your loop (pseudo-code below):
string s = "Hello, world!"
for i = 0 to s.Length / 2
char t = s[i]
s[i] = s[s.Length - 1 - t]
s[s.Length - 1 - i] = t
Which will swap the ends of the string to reverse it. Instead of looping through N items, you loop through a maximum of N / 2 items.