I was studying about pipes recently and saw this answer:
Connecting n commands with pipes in a shell?
I was intrigued about it and tried to make like a "dynamic" one, in which I introduce a string with n process and then execute the n process (i.e ls | sort). I was trying to tokenize, save in an array, but it did not work. Here is my code of my "tokenizer":
int main()
{
char str[] = "ls | sort";
int length = (sizeof(str) / sizeof(*str))-1;
int sizeCMD = 1; //If the string has zero pipe, it means it has at least 1 process
vector<char> tempV;
for (int i = 0; i < length; i++)
{
if (str[i] == '|')
{//If the string has one |, it means it has at least 2 process.
sizeCMD++;
}
tempV.push_back(str[i]);//I was going to do something else with this, but I forgot.
//cout<<i<<" "<<tempV.at(i)<<endl;
}
int j = 0;//Current position of the cmd
string comLetter = "";//it will save every single letter in certain conditions
string comLine = "";//it will save all the characters of comLetter in certain conditions
struct command cmd[sizeCMD];
const char *ls[2];
const char *sort[2];
const char *toCChar;
for (int i = 0; i < tempV.size(); i++)
{
if (tempV.at(i) != ' ' && tempV.at(i) != '|')
{//comLetter will only save characters that are not equal to blank or |.
//cout<<tempV.at(i);
comLetter += tempV.at(i);
//cout<< comLetter <<endl;
}
if (tempV.at(i) == ' ' || i == tempV.size() - 1)
{//comLine will save everything of comLetter when it detects a blank or the very end
//cout<<comLetter<<endl;
comLine = comLetter;
comLetter = "";
}
if (tempV.at(i) == '|' || i == tempV.size() - 1)
{//cmd will save everything of comLine when it detects a | or the very end.
//cout<<j<<endl;
cout << "." << comLine << "." << endl;
//cout<<i<<endl;
//cout<<toCChar<<endl;
if(comLine == "ls"){
toCChar = comLine.c_str();
ls[0] = toCChar;
ls[1] = 0; //THIS IF
cmd[0] = {ls}; //WORKS
}
if(comLine == "sort"){
sort[0] = "sort";
sort[1] = 0; //THIS IF
cmd[1] = {sort}; //WORKS
}
/*const char *ls[2];
cout<<toCChar<<endl;
ls[0] = toCChar;
ls[1] = 0;
cout<< *ls[0] << " - "<< endl;
cmd[j] = {ls};
//cout << cmd << endl;
comLine = "";*/
j++; //The position will move by one.
}
}
return fork_pipes(sizeCMD, cmd);
}
Everything made sense to me, until I found out that const char* can't be temporal as it needs the data, so I need to create 2 const char* arrays for 2 commands. That's why I've two arrays: *sort[] and *ls[], for sort and ls.
Also, I was wondering, why these lines get "ignored":
toCChar = comLine.c_str();
ls[0] = toCChar;
I'm struggling right now, if someone could please help/guide me on how to do it, I would appreciate that.
Related
I am attempting to extract output string from an OpenCV Matrix window and evaluate it, but it seems to return something similar to "someString\n" rather "someString". This renders it difficult to compare knowing there are (x) amounts of white spaces.
I tried:
creating a char array that omits the white spaces (I am aware that I'm only evaluating 5 indexes)
std::string redef;
char charArr[100] = {NULL};
strcpy_s(charArr, str.c_str());
for (int i = 0; i < 5; i++)
{
if (charArr[i] != ' ')
{
redef += charArr[i];
}
}
std::cout << "analyseAction ran:" << redef << "white-space?";
but the string returns something like
analyseAction ran:redefString
white-space?
Relevant code running in main function:
api->Recognize(0);
outText = api->GetUTF8Text();
analyseAction(outText);
bellow, just take note that the else statement runs since redef doesn't equal to "long" when long is shown visually in window.
void analyseAction(std::string str)
{
std::string redef;
char charArr[100] = {NULL};
strcpy_s(charArr, str.c_str());
for (int i = 0; i < 5; i++)
{
if (charArr[i] != ' ')
{
redef += charArr[i];
}
}
std::cout << "analyseAction ran:" << redef << "white-space?";
//alot of missing code, trying to show what is relevant
if (redef == "long") //check if it has white space after long, seems like it new line's
{
//NOTE FOR FUTURE: Stop being lazy and make this a function of its own
//BUY
std::cout << "Long ran";
for (int i = 0; i < a; i++) //no comma with first line so 0 element
{
context += inData[i];
}
x = std::stoi(context);
for (int i = a+1; i < a1; i++)
{
context += inData[i];
}
y = std::stoi(context);
simClick(x,y);
//BUY CONFIRM
for (int i = a1+1; i < b; i++) //starting from pipeline??
{
context += inData[i];
}
x = std::stoi(context);
for (int i = b+1; i < b1; i++) //starting with comma? +1 to fix
{
context += inData[i];
}
y = std::stoi(context);
simClick(x, y);
}
else
{
std::cout << "long does not match";
}
}
I am confused, why does the string appear to new line? And how can I successfully evaluate the output? I am a noobie in C++ so any help will be greatly appreciated.
As for why it's returning a string and a line break, I cannot answer that. But I can provide you an alternative system to what you are trying to accomplish. Remove your first for loop in the analyseAction function and in your if statement for "long" pass in... if(charArr[0] == 'l') {//do stuff} This does have a limit if you are assessing many words that start with "l", in this case assess the first two or three letters of the word so long they aren't less than 2 or 3 letter words. PS. this was written on mobile.
I was training on solving algorithms, I wrote a code but it won't compile
in (if) I can not check s[i]=='S' .
I'm trying to if s[i] is S character or not but I don't know where my problem is.
If I can't use this syntax, what could be a solution?
#include<iostream>
#include<string>
using namespace std;
int main()
{
double v_w=25,v_s=25,d_w=25,d_s=25;
int n;
cin>>n;
string s[]={"WSSS"};
int i ;
for (i=0; i<n; i++)
{
if( s[i] == "W" )
{
v_s += 50;
d_w = d_w + (v_w/2);
d_s = d_s + (v_s/2);
cout<<"1 \n";
}
if(s[i]=='W')
{
v_w +=50;
d_w = d_w + (v_w/2);
d_s = d_s + (v_s/2);
cout<<"2 \n";
}
return 0;
}
cout<< d_w<<endl<<d_s;
}
string s[]={"WSSS"}; means an array of strings which the first one is "WSSS".
What you need is:
std::string s="WSSS";
string s[] = {"Hello"} is an array of strings (well, of one string).
If you iterate over it, or index into it s[0] is "Hello".
Whereas
string s{"Hello"} is one string, which is made up of characters.
If you iterate over it, or index into it s[0], you will get 'H'.
To pre-empt all the other things that are going to go wrong when the string versus character problem is sorted, lets move the return 0; from the middle of the for loop.
Then let's think about what happens if the number n entered is larger than the length of the string:
int n;
cin>>n; //<- no reason to assume this will be s.length (0 or less) or even positive
string s{"WSSS"}; //one string is probably enough
int i ;
for(i=0;i<n;i++)
{
if( s[i] == 'W' ) //ARGGGGGGG may have gone beyond the end of s
{
In fact, let's just drop that for now and come back to it later. And let's use a range based for loop...
#include<iostream>
#include<string>
using namespace std;
int main()
{
double v_w = 25, v_s = 25, d_w = 25, d_s = 25;
string s{ "WSSS" };
for (auto && c : s)
{
if (c == 'W')
{
v_w += 50;
d_w = d_w + (v_w / 2);
d_s = d_s + (v_s / 2);
cout << "2 \n";
}
}
cout << d_w << '\n' << d_s << '\n'; //<- removed endl just because...
return 0;
}
s is an array of strings in this case it has only element:
string s[] = {"WSSS"};
so writing s[2]; // is Undefined behavior
your code will produce a UB if the user enters n greater than the number of elements in s:
n = 4;
for(i = 0; i < n; i++) // s[3] will be used which causes UB
{
if( s[i] == 'W' ) // s[i] is a string not just a single char
{
}
}
also as long as s is an array of strings then to check its elements check them as strings not just single chars:
if( s[i] == "W" ) // not if( s[i] == 'W' )
I think you wanted a single string:
string s = {"WSSS"};
because maybe you are accustomed to add the subscript operator to character strings:
char s[] = {"WSSS"};
if so then the condition above is correct:
if( s[i] == 'W' )
The original prompt was:
Write a program that keeps track of a speakers bureau. The program should use a
structure to store the following data about a speaker:
Name
Telephone Number
Speaking Topic
Fee Required
The program should use an array of at least 10 structures. It should let the user enter
data into the array, change the contents of any element, and display all the data stored
in the array. The program should have a menu-driven user interface.
Input Validation: When the data for a new speaker is entered, be sure the user enters
data for all the fields. No negative amounts should be entered for a speaker s fee.
The added prompt was:
I need this to expand the search pattern with the potential one character of letter or digit typos. Only one character maybe a typo, in any position Try these test patterns should get the following results:
0-9 is 0x30-0x39
a-z is 0x41-0x5A
A-Z is 0x61-0x7A (or lower case it)
And I can't get the added prompt to work with my current program.
No other characters in the search pattern may be changed.
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
bool print_one_typo(string input, string people[11], bool is_found[11])
{
bool found = false;
if (input[0] == '?')
{
char *strPtr = NULL;
for (int i = 0; i < 11; i++)
{
strPtr = strstr(people[i].c_str(), input.substr(1).c_str());
if (strPtr != NULL)
{
cout << "\t" << people[i] << endl;
found = true;
is_found[i] = true;
}
}
}
else
{
for (int i = 0; i < 11; i++)
{
bool match = true;
string str = people[i];
int value = str.find(input[0]);
for (int k = 0; k < input.length(); k++)
{
if (input[k] != '?' && input[k] != str[value++])
{
match = false;
break;
}
}
if (match && !is_found[i])
{
found = true;
cout << "\t" << people[i] << endl;
}
}
}
return found;
}
int main()
{
string people[11] = { "Becky Warren, 555-1223",
"Joe Looney, 555-0097",
"Geri Palmer, 555-8787",
"Lynn Presnell, 555-1225",
"Holly Gaddis, 555-8878",
"Sam Wiggins, 555-0998",
"Bob Kain, 555-8712",
"Tim Haynes, 555-7676",
"Warren Gaddis, 555-9037",
"Jean James, 555-9223",
"Ron Palmer, 555-7227" };
bool is_found[11] = { false };
string lookUp;
int i;
cout << "\t People and Phone numbers" << endl;
cout << "Enter name or phone number: ";
cin >> lookUp;
cout << "result: " << endl;
bool found = false;
bool output = false;
for (int i = 0; i < lookUp.length(); i++)
{
string local = lookUp;
found = print_one_typo(local.replace(i, 1, 1, '?'), people, is_found);
if (found) output = true;
}
if (!output)
cout << "No matching product was found" << endl;
return 0;
}
I think your code overthinks the problem. Also, you didn't specify if "typo" just means "wrong character", or a fuller range that includes dropped characters or inserted characters.
If you are only looking for matches with zero or one incorrect characters, but otherwise the same length, I think this code should do:
bool print_one_typo(string input, string people[11], bool is_found[11])
{
for (int i = 0; i < 11; i++)
{
if ( is_found[i] ) // Skip if it had already been found?
continue;
if ( input.length() != people[i].length() ) // Are they same length?
continue; // No: Skip it.
int typos = 0;
size_t len = input.length();
for (size_t j = 0; j != len && typos < 2; j++)
if ( input[j] != people[i][j] )
typos++;
if (typos < 2) // Fewer than 2 typos: We have a winner! Return it.
{
is_found[i] = true;
return true;
}
}
return false;
}
This code skips strings that differ in length, or which you're filtering out via the is_found[] array. Not sure why you're doing that, but I preserved that bit of your original code.
If it finds two strings that are the same length, it just compares them character by character, counting up typos. If it sees 2 or more typos, it skips to the next one. Otherwise, it takes the first string that's the same length but fewer than 2 typos.
My string is std::string str ("DDWD");
I want to change the corresponding to the following
D = [0-9] W = [a-z]
soo...("[0-9][0-9][A-Z][0-9]")
The replace method does not seem to accomade this, so i tried something like
string tmp = "DDDWD";
int len = 0;
len = tmp.length();
for( int i = 0; i < len; i++ )
{
if ( tmp[i] == 'D')
{
tmp.replace(i,1,"[0-9]");
i+=2;
}
}
However trying to change both letters D and W there was a problem and it wasent changing them all correctly?
Does anyone know a way how to change each letter at the same time to the corresponding string above?
Thankful for any help
Looks to me like you're just ending your loop early.
len = tmp.length();
for( int i = 0; i < len; i++ )
{
...so you save the length to iterate, and even if the string gets longer, you'll stop at the old length.
I think this would be cleaner if you used a separate string:
string tmp = "DDDWD";
string tmp2;
for (int i=0; i<tmp.size(); ++i)
{
if (tmp[i] == 'D')
tmp2 += "[0-9]";
else if (tmp[i] == 'W')
tmp2 += "[a-z]";
else
tmp2 += tmp[i];
}
tmp.swap(tmp2);
// or in C++11
// tmp = std::move(tmp2);
The replace method works with positions, not substrings. So replacing would be a two-step process: find first, then replace with the results of the find, until find no longer finds anything.
But the way you do it also works, if you run the loop backwards (start at the end and work your way down).
If you can afford it, use Boost's String Algo library. It has lots of useful algorithms on strings. Your problem would then read:
// #include <boost/algorithm/string/replace.hpp>
std::string tmp = "DDDWD";
boost::replace_all( tmp, "D", "[0-9]" );
boost::replace_all( tmp, "W", "[a-z]" );
int main()
{
std::string tmp = "DDDWD";
char *tmp2=new char(5*(strlen(tmp.c_str()) +1));
cout << "tmp is " << tmp;
for (int i=0; i<tmp.size(); ++i)
{
if (tmp[i] == 'D' && i==0)
tmp2 = strcpy(tmp2,"[0-9]");
else if(tmp[i] == 'D' && i!=0)
tmp2 = strcat(tmp2,"[0-9]");
else if (tmp[i] == 'W' && i==0)
tmp2 = strcpy(tmp2,"[a-z]");
else if (tmp[i] == 'W' && i!=0)
tmp2 = strcat(tmp2,"[a-z]");
}
cout << "tmp2 is :" << tmp2;
getchar();
}
Hi there I'm reading a string and breaking each word and sorting it into name email and phone number. with the string joe bloggs joeblog#live.com 12345. But once i break everything down, the individual separated variables which hold the name,email and phone number have garbage characters at the end of them. I cant figure out why.
test file
//test file
#include <iostream>
#include <string>
#include "iofunc.h"
using namespace std;
int main(){
string str1 = "joe bloggs joeblog#live.com 12345";
iofunc func;
cout<<"|-----------------------getname DEMONSTRATION------------------|\n" << endl;
func.getName(str1);
cout<<"the names are: " << func.glob_name << endl;
cout<<"\n|-----------------------getphone DEMONSTRATION------------------|\n" << endl;
func.getPhone(str1);
cout<<"the phone number is:" << func.glob_phone << endl;
cout<<"\n|-----------------------getemail DEMONSTRATION------------------|\n" << endl;
func.getEmail(str1);
cout<<"the email address is:" << func.glob_email << endl;
return 0;
}
here's my get name function, the class is too big to scroll through:)
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
}
}
basic jist of all that is, im using the function called lineProcess to figure out whether there is an email, phone and name in the argument string, And the numberofNames functions gives how many names there are so that I can act accordingly.
I had to use char name_temp to copy just the names from string so that I can extract just that and assign it to the string variable named glob_name. It copies everything i need but it gives me that garbage after each extracted string.
any idea?.
EDITED
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
int index_track = 0;
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
}
}
When you do things like this:
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
You are copying the characters of the string to name_tmp, but not the 0 at the end which terminates the string.
add to each new string '\0' end-of string symbol
Garbage characters at the end of a string could indicate that you're not null-terminating the string (ending it with a 0x00 byte). This causes the string to continue reading until the next null character, which is actually past where the string's memory ends. This could even cause a segmentation fault in some cases.
You can fix this by adding '\0' to the end of each new string you create. Note that you will have to allocate a string one byte larger now, to hold that new ending character.
The others have pointed you in the right direction, you aren't appropriately terminating your c strings. Declaring a char array of length 80 just points to a block of memory, it doesn't initialise the array in any way, this means that unless you /0 terminate the string you copy into it, you'll get all the crap lying around on the end up to the 80 characters.
I've not written C++ in probably 15 years so the code below may not even work but hopefully it'll give you some ideas for a more elegant and maintainable solution.
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
string name_temp;
// Let's assemble a c-str version if the inbound arg string
char* cstr;
cstr = new char [arg.size()+1];
strcpy (cstr, arg.c_str());
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
glob_name = arg;
}
if (special_condition == false){
// Assuming there's at least 1 name, which we have to otherwise the original
// code may never set glob_name, let's use the C String function strtok
// to tokenise our newly created c string at each " ".
// Grab the first name.
name_temp = string(strtok(cstr, " "));
for (int i = 1; i < name_count; i++) {
// Grab names 2 to name_count as required and append them to name_temp
// We need to reinsert the space as strtok doesn't grab it.
name_temp += " " + string(strtok(NULL, " "));
}
// Assign our final name to glob_name
glob_name = name_temp;
}
}