for example:
Reading file input and stored into
char fileInput[200];
then I converted it to some sort of string array using
string fileStrArr(fileInput);
the testing output from the file looks like this : 50014002600325041805
how can I use substring with a loop to get every 4-digit char and convert it to a number such as "5001" "4002" "6003"...? so I think I need to make string array into a string first?
To convert a character array to an object of type std::string is very simply
std::string s( fileInput );
provided that fileInput is zero terminated. Otherwise you have to use some other std::string constructor
If I have understood you correctly you need something like the following
#include <iostream>
#include <string>
#include <vector>
int main()
{
const size_t N = 4;
std::string s( "50014002600325041805" );
std::vector <int> v;
for ( size_t i = 0; i != s.size(); )
{
std::string t = s.substr( i, N );
v.push_back( std::stoi( t ) );
i += t.size();
}
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The program output is
5001 4002 6003 2504 1805
When i am using StrSplit function with a constant string it works great. but when i read the line from a file and then use it as string for StrSplit function my program crashes. the following is the code and the error screen shot.
string Read_from_file(){
//load the text file and put it into a single string:
std::ifstream in("test.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string test = buffer.str();
std::cout << test << std::endl << std::endl;
return test;
}
// split the given string according to give delimeters
vector<string> &StrSplit( string inStr, string sepStr, vector<string> &outStrVec) {
char * comp;
char * buffer = new char[ strlen( inStr.c_str() ) ];
strcpy( buffer, inStr.c_str() );
comp = strtok ( buffer, sepStr.c_str() );
while ( comp != NULL ) {
outStrVec.push_back(comp);
comp = strtok ( NULL, sepStr.c_str() );
}
delete[] comp;
delete[] buffer;
return outStrVec;
}
vector<string> StrSplit( string inStr, string sepStr ) {
vector<string> outStrVec;
return StrSplit( inStr, sepStr, outStrVec );
![enter image description here][2]}
int main( ) {
Read_from_file();
string fileinput = Read_from_file();
vector<string> v;
string inStr = fileinput;
v = StrSplit( inStr, "|#$ *#.&\"!^01" );
for (unsigned int i = 0; i < v.size(); ++i) {
cout << v[i] << '\n';
}
}
The buffer is too small to contain the string including the terminating 0 character.
Change
char * buffer = new char[ strlen( inStr.c_str() ) ];
to
char * buffer = new char[ strlen( inStr.c_str() ) + 1];
And don't call delete on pointers you didn't new (remove delete[] comp).
Actually, I would never use strtok in C++.
For example, if I have
string x = "dog:cat";
and I want to extract everything after the ":", and return cat. What would be the way to go about doing this?
Try this:
x.substr(x.find(":") + 1);
I know it will be super late but I am not able to comment accepted answer. If you are using only a single character in find function use '' instead of "".
As Clang-Tidy says The character literal overload is more efficient.
So
x.substr(x.find(':') + 1)
The accepted answer from rcs can be improved. Don't have rep so I can't comment on the answer.
std::string x = "dog:cat";
std::string substr;
auto npos = x.find(":");
if (npos != std::string::npos)
substr = x.substr(npos + 1);
if (!substr.empty())
; // Found substring;
Not performing proper error checking trips up lots of programmers. The string has the sentinel the OP is interested but throws std::out_of_range if pos > size().
basic_string substr( size_type pos = 0, size_type count = npos ) const;
#include <iostream>
#include <string>
int main(){
std::string x = "dog:cat";
//prints cat
std::cout << x.substr(x.find(":") + 1) << '\n';
}
Here is an implementation wrapped in a function that will work on a delimiter of any length:
#include <iostream>
#include <string>
std::string get_right_of_delim(std::string const& str, std::string const& delim){
return str.substr(str.find(delim) + delim.size());
}
int main(){
//prints cat
std::cout << get_right_of_delim("dog::cat","::") << '\n';
}
something like this:
string x = "dog:cat";
int i = x.find_first_of(":");
string cat = x.substr(i+1);
Try this:
string x="dog:cat";
int pos = x.find(":");
string sub = x.substr (pos+1);
cout << sub;
What you can do is get the position of ':' from your string, then retrieve everything after that position using substring.
size_t pos = x.find(":"); // position of ":" in str
string str3 = str.substr (pos);
#include <string>
#include <iostream>
std::string process(std::string const& s)
{
std::string::size_type pos = s.find(':');
if (pos!= std::string::npos)
{
return s.substr(pos+1,s.length());
}
else
{
return s;
}
}
int main()
{
std::string s = process("dog:cat");
std::cout << s;
}
Try this one..
std::stringstream x("dog:cat");
std::string segment;
std::vector<std::string> seglist;
while(std::getline(x, segment, ':'))
{
seglist.push_back(segment);
}
I need to search a string and edit the formatting of it.
So far I can replace the first occurrence of the string, but I am unable to do so with the next occurrences of this string.
This is what I have working, sort of:
if(chartDataString.find("*A") == string::npos){ return;}
else{chartDataString.replace(chartDataString.find("*A"), 3,"[A]\n");}
If it doesn't find the string, nothing prints at all, so that's not good.
I know I need to loop through the entire string chartDataString and replace all occurrences. I know there are a lot of similar posts to this but I don't understand (like this Replace substring with another substring C++)
I've also tried to do something like this to loop over the string:
string toSearch = chartDataString;
string toFind = "*A:";
for (int i = 0; i<toSearch.length() - toFind.length(); i++){
if(toSearch.substr(i, toFind.length()) == toFind){
chartDataString.replace(chartDataString.find(toFind), 3, "[A]\n");
}
}
EDIT
taking into consideration suggestions, this in theory should work, but I don't know why it doesn't
size_t startPos=0;
string myString = "*A";
while(string::npos != (startPos = chartDataString.find(myString, startPos))){
chartDataString.replace(chartDataString.find(myString, startPos), 3, "*A\n");
startPos = startPos + myString.length();
}
try the following
const std::string s = "*A";
const std::string t = "*A\n";
std::string::size_type n = 0;
while ( ( n = chartDataString.find( s, n ) ) != std::string::npos )
{
chartDataString.replace( n, s.size(), t );
n += t.size();
}
In case boost is available, you can use the following:
std::string origStr = "this string has *A and then another *A";
std::string subStringToRemove = "*A";
std::string subStringToReplace = "[A]";
boost::replace_all(origStr , subStringToRemove , subStringToReplace);
To perform the modification on the original string, OR
std::string result = boost::replace_all_copy(origStr , subStringToRemove , subStringToReplace);
To perform the modifications without modifying the original string.
Use std::regex_replace available with C++11. This does exactly what you want and more.
https://en.cppreference.com/w/cpp/regex/regex_replace
std::string const result = std::regex_replace( chartDataString, std::regex( "\\*A" ), "[A]\n" );
/// Returns a version of 'str' where every occurrence of
/// 'find' is substituted by 'replace'.
/// - Inspired by James Kanze.
/// - http://stackoverflow.com/questions/20406744/
std::string replace_all(
const std::string & str , // where to work
const std::string & find , // substitute 'find'
const std::string & replace // by 'replace'
) {
using namespace std;
string result;
size_t find_len = find.size();
size_t pos,from=0;
while ( string::npos != ( pos=str.find(find,from) ) ) {
result.append( str, from, pos-from );
result.append( replace );
from = pos + find_len;
}
result.append( str, from , string::npos );
return result;
/*
This code might be an improvement to James Kanze's
because it uses std::string methods instead of
general algorithms [as 'std::search()'].
*/
}
int main() {
{
std::string test = "*A ... *A ... *A ...";
std::string changed = "*A\n ... *A\n ... *A\n ...";
assert( changed == replace_all( test, "*A", "*A\n" ) );
}
{
std::string GB = "My gorila ate the banana";
std::string gg = replace_all( GB, "gorila", "banana" );
assert( gg == "My banana ate the banana" );
gg = replace_all( gg, "banana", "gorila" );
assert( gg == "My gorila ate the gorila" );
std::string bb = replace_all( GB, "banana", "gorila" );
assert( gg == "My gorila ate the gorila" );
bb = replace_all( bb, "gorila" , "banana" );
assert( bb == "My banana ate the banana" );
}
{
std::string str, res;
str.assign( "ababaabcd" );
res = replace_all( str, "ab", "fg");
assert( res == "fgfgafgcd" );
str="aaaaaaaa"; assert( 8==str.size() );
res = replace_all( str, "aa", "a" );
assert( res == "aaaa" );
assert( "" == replace_all( str, "aa", "" ) );
str = "aaaaaaa"; assert( 7==str.size() );
res = replace_all( str, "aa", "a" );
assert( res == "aaaa" );
str = "..aaaaaa.."; assert( 10==str.size() );
res = replace_all( str, "aa", "a" );
assert( res == "..aaa.." );
str = "baaaac"; assert( 6==str.size() );
res = replace_all( str, "aa", "" );
assert( res == "bc" );
}
}
The find function takes an optional second argument: the position from which to begin searching. By default this is zero.
A good position to begin searching for the next match is the position where the previous replacement was inserted, plus that replacement's length. For instance if we insert a string of length 3 at position 7, then the next find should begin at position 10.
If the search string happens to be a substring of the replacement, this approach will avoid an infinite loop. Imagine if you try to replace all occurrences of log with analog, but don't skip over the replacement.
It's fairly awkward (and probably not too efficient) to do it in
place. I usually use a function along the lines of:
std::string
replaceAll( std::string const& original, std::string const& from, std::string const& to )
{
std::string results;
std::string::const_iterator end = original.end();
std::string::const_iterator current = original.begin();
std::string::const_iterator next = std::search( current, end, from.begin(), from.end() );
while ( next != end ) {
results.append( current, next );
results.append( to );
current = next + from.size();
next = std::search( current, end, from.begin(), from.end() );
}
results.append( current, next );
return results;
}
Basically, you loop as long as you can find an instance of
from, appending the intermediate text and to, and advancing
to the next instance of from. At the end, you append any text
after the last instance of from.
(If you're going to do much programming in C++, it's probably
a good idea to get used to using iterators, like the above,
rather than the special member functions of std::string.
Things like the above can be made to work with any of the C++
container types, and for this reason, are more idiomatic.)
Below is a complete display of how find, string::replace and replace working.
There is no direct implementation of replaceAll in cpp.
We can tweak replace to perform our intent:
string original = "A abc abc abc A";
string test = original;
cout << endl << "Original string: " << original; //output: A abc abc abc A
//FINDING INDEX WHERE QUERY SUBSTRING FOUND
int index = test.find("a");
cout << endl << "index: " << index; //output: 2
int outOfBoundIndex = test.find("xyz");
cout << endl << "outOfBoundIndex: " << outOfBoundIndex; //output: -1
//REPLACE SINGLE OCCURENCES
string queryString = "abc";
int queryStringLength = queryString.size();
index = test.find(queryString);
if(index > -1 && index < (test.size() - 1))
test.replace(index, queryStringLength, "xyz");
cout << endl << endl << "first occurrence \'abc\' replaced to \'xyz\': " << test; //output: A xyz abc abc A
//REPLACE ALL OCCURRENCES
test = original;
//there is a cpp utility function to replace all occurrence of single character. It will not work for replacing all occurences of string.
replace(test.begin(), test.end(), 'a', 'X');
cout << endl << endl << "Replacing all occurences of character \'a\' with \'X\': " << test; //output: A Xbc Xbc Xbc A
test = original;
index = test.find("abc");
while(index > -1 && index < (test.size() - 1)){
test.replace(index, queryStringLength, "xyz");
index = test.find("abc");
}
cout << endl << "replaceAll implementation: " << test; //output: A xyz xyz xyz A
string replaceAll(string del, string replace, string line){
int len=del.length();
string output="[Programming Error]";
if(line.find(del)!=-1){
do{
output=line.replace(line.find(del),len,replace);
}while(output.find(del)!=-1);
}
return output;
}
If ever the strings you need to invert are not of the same size:
void Replace::replace(std::string & str, std::string const & s1, std::string const & s2)
{
size_t pos = 0;
while ((pos = str.find(s1, pos)) != std::string::npos)
{
str.erase(pos, s1.length());
str.insert(pos, s2);
pos += s2.length();
}
}
I have a string "abc=14,22 xyz=33, tdc=48" in a file. How can I separate it into strings and their corresponding values in C++?
like--
abc = 14,22
xyz = 33
tdc = 48
char * astr = "abc=14,22 xyz=33, tdc=48";
int abc1, abc2,xyz,tdc;
sscanf(astr,"abc=%d,%d xyz=%d, tdc=%d",&abc1,&abc2,&xyz,&tdc);
If you need to read a string from a file you could use std::ifstream:
std::ifstream fs( "some_file.txt" );
std::string input_string;
while ( getline(fs, input_string) ) {
// parse a string
}
Then, just for fun, a version with regular expressions how you could parse an input string:
#include <iostream>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
int main()
{
const std::string input_string = "abc=14,22 xyz=33, tdc=48";
// this is a regular expression that will parse the input_string
boost::regex expr( "^abc=(\\d+,\\d+) xyz=(\\d+), tdc=(\\d+)$" );
boost::match_results<std::string::const_iterator> what;
if ( regex_search( input_string, what, expr )) {
// we'll get here only if Regex will find all required parts
// abc = ?
std::string abc_str( what[1].first, what[1].second );
// convert abc to a float variable
std::replace( abc_str.begin(), abc_str.end(), ',', '.' );
float abc = boost::lexical_cast<float>( abc_str );
// xyz = ?
std::string xyz_str( what[2].first, what[2].second );
// convert xyz to an int variable
int xyz = boost::lexical_cast<int>( xyz_str );
// tdc = ?
std::string tdc_str( what[3].first, what[3].second );
// convert tdc to an int variable
int tdc = boost::lexical_cast<int>( tdc_str );
// check result
std::cout << abc << std::endl;
std::cout << xyz << std::endl;
std::cout << tdc << std::endl;
}
return 0;
}
In your concrete question using Regex is overkill, but in more complex cases it could be useful.