extracting substring between two '\n' characters into a seperate array - c++

I have a 100 char string with few '\n' characters in it , I want to extract the characters between the first '\n' and the second '\n' and store them in another char array , how can i do that?
please note that i cant use iostreams or vectors as I am using AVR GCC. i can only use strok() or strcpy()

If to use character arrays then you can use the following approach
#include <iostream>
#include <cstring>
int main()
{
char s[100] = "begin\nmiddle\nend";
char t[100];
t[0] = '\0';
if ( char *p = strchr( s, '\n' ) )
{
if ( char *q = strchr( ++p, '\n' ) )
{
std::strncpy( t, p, q - p );
t[q - p] = '\0';
}
else
{
strcpy( t, p );
}
}
std::cout << "\"" << t << "\"" << std::endl;
}
The program output is
"middle"
If you want to get an array of strings separated by the new line character then you can use the following approach
#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iterator>
int main()
{
char s[100] = "begin\nmiddle\nend";
std::istringstream is( s );
std::vector<std::string> v( ( std::istream_iterator<std::string>( is ) ),
std::istream_iterator<std::string>() );
for ( const std::string &item : v ) std::cout << '\"' << item << '\"' << std::endl;
}
The program output is
"begin"
"middle"
"end"
But it does not make great sense to use this approach if you need just to copy one substring from one character array to another.

A basic Version is this one:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using std::string;
using std::cout;
void base_ansi_c()
{
const char * source = "one\ntwo\nthree\n";
char target[1024];
const char * c;
for (c = source; c && *c != 0 && *c != '\n'; ++c); //skip until first '\n'
if (c && *c == '\n') ++c; // skip '\n'
int n = 0;
for (; c && *c != 0 && *c != '\n' && n < 1024; ++c, ++n) //copy until second '\n'
{
target[n] = *c;
}
target[n] = 0;
cout << "'" << target << "'\n";
}
void base_cpp_sstream()
{
std::vector<string> cpp_array;
std::string test = "one\ntwo\nthree\n";
std::istringstream is(test);
std::string part;
while (std::getline(is, part, '\n'))
{
cpp_array.emplace_back(part);
std::cout << " " << part << " ";
}
std::cout << "\n";
std::cout << "The second element is: '" << cpp_array.at(1) << "'\n";
}
int main()
{
std::cout << "\nbase_cpp_sstream\n";
base_cpp_sstream();
std::cout << "\nbase_ansi_c\n";
base_ansi_c();
}
If it gets more complex you may want to switch to either boost::tokenizer or boost::spirit::qi.
Since you asked for a different version where the positions are more relevant to the algorithm I added an ansi-c style iterating through the string.
Edit: Some detail about the code above as you requested in the comment. I think explaining this line for (c = source; c && *c != 0 && *c != '\n'; ++c); will be enough to get you started.
The statement c = source just copies the pointer at the beginning of the loop.
At every iteration including the first the following is checked: c && *c != 0 && *c != '\n' The detail here is that c will be dereferenced so it can not be (char*)0. 0 is false, every other value is true. If c is false the chained together values using && are not evaluated. So there is no risk of dereferencing a null pointer. *c != 0 checks if the end of the c-string is reached. In that case no \n was found. *c != '\n' checks if a new line character is reached.
At the end of an iteration the pointer is incremented. ++c this moves the c pointer to the next element of the array. Since c is a char the pointer is incremented by 1. sizeof(char) evaluates to 1. (always). If the array elements were of a different type the increment would also move the pointer to the next element. (does not work with void*).
If '\n' is found there is no increment afterwards. The for loop just ends. since c was declared outside of the loop the value remains preserved and can be used by the subsequent algorithms.

Related

Am replacing the first occurrence of a string, how can I replace all occurrences?

I have already bulid the basic structure by using the loop + replace,In C++, the str.replace is only to replace single string, however, in some cases, we need to replace all the same string, My code can compile successfully and can output to the screen, but it seems that it does not replace successfully.
Thanks in advance
here's my code:
#include <iostream>
#include <fstream>
#include <string>
int main(void)
{
// initialize
std::ofstream fout;
std::ifstream fin;
fout.open("cad.dat");
fout << "C is a Computer Programming Language which is used worldwide, Everyone should learn how to use C" << std::endl;
fin.open("cad.dat");
std::string words;
getline(fin,words);
std::cout << words << std::endl;
while(1)
{
std::string::size_type pos(0);
if (pos = words.find("C") != std::string::npos && words[pos+1] != ' ') //the later one is used to detect the single word "C"
{
words.replace(pos, 1, "C++");
}
else
{
break;
}
}
std::cout << words;
}
You can simplify your program by just using regex as follows:
std::regex f("\\bC\\b");
words = std::regex_replace(words, f, "C++"); // replace "C" with "C++"
Then there is no need for a while loop as shown in the below program:
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
int main(void)
{
// initialize
std::ofstream fout;
std::ifstream fin;
fout.open("cad.dat");
fout << "C is a Computer Programming Language which is used worldwide, Everyone should learn how to use C" << std::endl;
fin.open("cad.dat");
std::string words;
getline(fin,words);
std::cout << words << std::endl;
std::regex f("\\bC\\b");
words = std::regex_replace(words, f, "C++"); // replace "C" with "C++"
std::cout << words;
}
You need to save pos and use it for the following find operations but you currently initialize it to 0 every iteration in the while loop.
You could replace the while while loop with this for example:
for(std::string::size_type pos = 0;
(pos = words.find("C", pos)) != std::string::npos; // start find at pos
pos += 1) // skip last found "C"
{
if(pos + 1 == words.size() || words[pos + 1] == ' ')
words.replace(pos, 1, "C++");
}
Note: This will replace the C in words ending with C too, for example an acronym like C2C will become C2C++. Also, a sentence ending with C. would not be handled. To handle these cases you could add a check for the character before the found C too and add punctuation to the check.
Example:
#include <cctype> // isspace, ispunct
#include <iostream>
#include <string>
int main()
{
std::string words = "C Computer C2C C. I like C, because it's C";
std::cout << words << '\n';
// a lambda to check for space or punctuation characters:
auto checker = [](unsigned char ch) {
return std::isspace(ch) || std::ispunct(ch);
};
for(std::string::size_type pos = 0;
(pos = words.find("C", pos)) != std::string::npos;
pos += 1)
{
if( (pos == 0 || checker(words[pos - 1])) &&
(pos + 1 == words.size() || checker(words[pos + 1]))
) {
words.replace(pos, 1, "C++");
}
}
std::cout << words << '\n';
}
Output:
C Computer C2C C. I like C, because it's C
C++ Computer C2C C++. I like C++, because it's C++

Lowercasing Capital Letters in char array[] in C++ through Pointers

I am trying to use pointers to recursively lowercase all capital letters
using the C++ programming language. Below is the code snippet:
// Example program
#include <iostream>
#include <string>
using namespace std;
void all_lower(char* input) {
if ( *input ) {
cout << input << endl;
return;
}
if ( *input >= 'A' && *input <= 'Z') {
*input += 32; // convert capital letter to lowercase
}
cout << *input << endl;
all_lower(++input); // simply move to next char in array
}
int main() {
char test[] = "Test";
all_lower(test);
return 0;
}
The output ends up being:
"Test"
even though I tried to increase the ASCII code value of the element by 32.
You are exiting the function on the first non-null character detected, which is 'T', and then you output the entire array before exiting, so you are seeing the original unmodified input. You are not recursing through the array at all. You need to recurse through the array until you reach the null terminator.
You need to change this:
if ( *input ) {
cout << input << endl;
return;
}
To this instead:
if ( *input == 0 ) {
return;
}
Then the function will work as expected.
That being said, I suggest you remove the cout statements from the function, and do a single cout in main() after the function has exited. This will speed up the function, and prove that the content of the test[] array is actually being modified:
#include <iostream>
using namespace std;
void all_lower(char* input)
{
if ( *input == 0 ) {
return;
}
if ( *input >= 'A' && *input <= 'Z') {
*input += 32; // convert capital letter to lowercase
}
all_lower(++input); // simply move to next char in array
}
int main()
{
char test[] = "TEST";
cout << "Before: " << test << endl;
all_lower(test);
cout << "After: " << test << endl;
return 0;
}
Live Demo
And, since you are using C++, consider removing all_lower() altogether and use the STL std::transform() algorithm instead:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
char test[] = "TEST";
cout << "Before: " << test << endl;
transform(test, test+4, test, [](char ch){ return tolower(ch); });
cout << "After: " << test << endl;
return 0;
}
Live Demo
Something short and easy:
#include <iostream>
#include <string>
using namespace std;
void all_lower(const char* input) {
if (!*input) {
std::cout << std::endl;
return;
}
std::cout << (char)(std::isalpha(*input) ? tolower(*input) : *input);
all_lower(++input); // simply move to next char in array
}
int main() {
all_lower("Test");
return 0;
}

How do I swap chars of a whole sentence with user input in C++?

I want to take input from user in
char input[200];
Then I want to swap each character of that input according to
a='y'; b='b'; c='j'; d='m'; e='x'; f='f'; g='w'; h='i';
i='v'; j='c'; k='l'; l='u'; m='t'; n='a'; o='k'; p='h';
q='d'; r='p'; s='s'; t='n'; u='z'; v='q'; w='e'; x='r';
y='o'; z='g';
For example if the input is
hello
The output will be
ixuuk
I want to code in C++ using for loops and arrays.
I suggest you use a lookup array:
char output = conversion[input_char];
You can simplify the array to 26 letters by using some arithmetic:
char output = conversion[input_char - 'a'];
The expression input_char - 'a' makes the letter a refer to the first slot in the conversion array.
Here's an example of the array:
static const char conversion[] =
{'b', 'y', 'c', 'k', 'f', /*...*/, 'a'};
Using the above code, if input is a, the output will be b. For input of b, the output will be y, and so on.
No need to swap. Remember that swapping changes values. I believe you want conversion or translation instead.
Here is a demonstrative program that shows how it could be done
#include <iostream>
#include <cstring>
#include <utility>
int main()
{
std::pair<const char *, const char *> cipher =
{
"abcdefghijklmnopqrstuvwxyz",
"ybjmxfwivclutakhdpsnzqerog"
};
const size_t N = 200;
char input[N];
input[0] = '\0';
std::cin.getline( input, sizeof( input ) );
std::cout << '\"' << input << '\"' << std::endl;
for ( char *p = input; *p; ++p )
{
if ( const char *q = std::strchr( cipher.first, *p ) )
{
*p = cipher.second[q - cipher.first];
}
}
std::cout << '\"' << input << '\"' << std::endl;
return 0;
}
The program output is
"Hello"
"Hxuuk"
You could also use functions tolower or toupper to convert initially characters of the source string to some case.
Solved the problem
#include <iostream>
#include <cstring>
#include <utility>
int main()
{
std::pair<const char *, const char *>
cipher ("abcdefghijklmnopqrstuvwxyz",
"ybjmxfwivclutakhdpsnzqerog");
const size_t N = 200;
char input[N];
input[0] = '\0';
std::cin.getline( input, sizeof( input ) );
std::cout << '\"' << input << '\"' << std::endl;
for ( char *p = input; *p; ++p )
{
if ( const char *q = std::strchr( cipher.first, *p ) )
{
*p = cipher.second[q - cipher.first];
}
}
std::cout << '\"' << input << '\"' << std::endl;
return 0;
}
Special thanks to #Vlad from Moscow
i suggest you use the nested loop.
create an array of strings having all the alphabets.
then create another array of strings having all the characters you want to change with the alphabets in the same order of the alphabets.
#include <iostream>
using namespace std;
int main()
{
string alphabets="abcdefghijklmnopqrstuvwxyz" ,
cipher="ybjmxfwivclutakhdpsnzqerog" , word , newword="" ;
cin>>word;
newword=word;
for(int i=0;i<26;i++)
{
for(int j=0;j<26;j++)
{
if(word[i]==alphabets[j])
{
newword[i]=cipher[j];
break;
}
}
}
cout<<newword;
return 0;
}

restore runtime unicode strings

I'm building an application that receives runtime strings with encoded unicode via tcp, an example string would be "\u7cfb\u8eca\u4e21\uff1a\u6771\u5317 ...". I have the following but unfortunately I can only benefit from it at compile time due to: incomplete universal character name \u since its expecting 4 hexadecimal characters at compile time.
QString restoreUnicode(QString strText)
{
QRegExp rx("\\\\u([0-9a-z]){4}");
return strText.replace(rx, QString::fromUtf8("\u\\1"));
}
I'm seeking a solution at runtime, I could I foreseen break up these strings and do some manipulation to convert those hexadecimals after the "\u" delimiters into base 10 and then pass them into the constructor of a QChar but I'm looking for a better way if one exists as I am very concerned about the time complexity incurred by such a method and am not an expert.
Does anyone have any solutions or tips.
You should decode the string by yourself. Just take the Unicode entry (rx.indexIn(strText)), parse it (int result; std::istringstream iss(s); if (!(iss>>std::hex>>result).fail()) ... and replace the original string \\uXXXX with (wchar_t)result.
For closure and anyone who comes across this thread in future, here is my initial solution before optimising the scope of these variables. Not a fan of it but it works given the unpredictable nature of unicode and/or ascii in the stream of which I have no control over (client only), whilst Unicode presence is low, it is good to handle it instead of ugly \u1234 etc.
QString restoreUnicode(QString strText)
{
QRegExp rxUnicode("\\\\u([0-9a-z]){4}");
bool bSuccessFlag;
int iSafetyOffset = 0;
int iNeedle = strText.indexOf(rxUnicode, iSafetyOffset);
while (iNeedle != -1)
{
QChar cCodePoint(strText.mid(iNeedle + 2, 4).toInt(&bSuccessFlag, 16));
if ( bSuccessFlag )
strText = strText.replace(strText.mid(iNeedle, 6), QString(cCodePoint));
else
iSafetyOffset = iNeedle + 1; // hop over non code point to avoid lock
iNeedle = strText.indexOf(rxUnicode, iSafetyOffset);
}
return strText;
}
#include <assert.h>
#include <iostream>
#include <string>
#include <sstream>
#include <locale>
#include <codecvt> // C++11
using namespace std;
int main()
{
char const data[] = "\\u7cfb\\u8eca\\u4e21\\uff1a\\u6771\\u5317";
istringstream stream( data );
wstring ws;
int code;
char slashCh, uCh;
while( stream >> slashCh >> uCh >> hex >> code )
{
assert( slashCh == '\\' && uCh == 'u' );
ws += wchar_t( code );
}
cout << "Unicode code points:" << endl;
for( auto it = ws.begin(); it != ws.end(); ++it )
{
cout << hex << 0 + *it << endl;
}
cout << endl;
// The following is C++11 specific.
cout << "UTF-8 encoding:" << endl;
wstring_convert< codecvt_utf8< wchar_t > > converter;
string const bytes = converter.to_bytes( ws );
for( auto it = bytes.begin(); it != bytes.end(); ++it )
{
cout << hex << 0 + (unsigned char)*it << ' ';
}
cout << endl;
}

prefix to infix on stack

I'm trying to implement prefix to infix in c++, that's what i've got so far. The input should be for example something like this:
/7+23
And the ouput:
7/(2+3) or (7/(2+3))
But instead I get:
(/)
That's the code I wrote so far:
void pre_to_in(stack<char> eq) {
if(nowe.empty() != true) {
char test;
test = eq.top();
eq.pop();
if(test == '+' || test == '-' || test == '/' || test == '*') {
cout << "(";
pre_to_in(eq);
cout << test;
pre_to_in(eq);
cout << ")";
} else {
cout << test;
}
}
}
// somewhere in main()
char arr[30];
stack<char> stosik;
int i = 0;
cout << "write formula in prefix notation\n";
cin >> arr;
while(i < strlen(arr)) {
stosik.push(arr[i]);
i++;
}
pre_to_in(stc);
This is a stack. First in, last out. You need reverse input string "32+7/".
You use many stacks. In every enter to pre_to_in() stack is copied. Use reference or pointer, ex: void pre_to_in(stack<char> &eq);
Thats all.
P.S. Unify names (s/nowe/eq/g && s/stc/stosik/g)
cin >> arr;
only reads one "word" of input, not a whole line. Here it's only getting the first slash character.
not sure if you are looking for such solution, anyway for the input you've mentioned it gives the output from you post
it reads tokens from std input
I've built it now under Visual Studio 2005 - to terminate input press Enter, Ctrl+Z, Enter
but on other compilers termination may work in another way
#include <algorithm>
#include <deque>
#include <iostream>
#include <string>
typedef std::deque< std::string > tokens_t;
void pre_to_in( tokens_t* eq )
{
if ( !eq->empty() ) {
const std::string token = eq->front();
eq->pop_front();
if ( ( token == "+" ) || ( token == "-" ) || ( token == "/" ) || ( token == "*" ) ) {
std::cout << "(";
pre_to_in( eq );
std::cout << token;
pre_to_in( eq );
std::cout << ")";
} else {
std::cout << token;
}
}
}
int main()
{
std::cout << "write formula in prefix notation" << std::endl;
tokens_t tokens;
std::copy(
std::istream_iterator< std::string >( std::cin ),
std::istream_iterator< std::string >(),
std::back_inserter( tokens ) );
pre_to_in( &tokens );
}