i need to create a function that will accept a directory path. But in order for the compiler to read backslash in i need to create a function that will make a one backslash into 2 backslash.. so far this are my codes:
string stripPath(string path)
{
char newpath[99999];
//char *pathlong;
char temp;
strcpy_s(newpath, path.c_str());
//pathlong = newpath;
int arrlength = sizeof(newpath);
for (int i = 0; i <= arrlength ;i++)
{
if(newpath[i] == '\\')
{
newpath[i] += '\\';
i++;
}
}
path = newpath;
return path;
}
this code receives an input from a user which is a directory path with single backslash.
the problem is it gives a dirty text output;
int arrlength = sizeof(newpath); causes the size of your entire array (in chars) to be assigned to arrlength. This means you are iterating over 99999 characters in the array, even if the path is shorter (which it probably is).
Your loop condition also allows goes one past the bounds of the array (since the last (99999th) element is actually at index 99998, not 99999 -- arrays are zero-based):
for (int i = 0; newpath[i]] != '\0'; i++)
Also, there is no reason to copy the string into a character array first, when you can loop over the string object directly.
In any case, there is no need to escape backslashes from user input. The backslash is a single character like any other; it is only special when embedded in string literals in your code.
In this line:
if(newpath[i] = '\\')
replace = with ==.
In this line:
newpath[i] += '\\';
This is supposed to add a \ into the string (I think that's what you want), but it actually does some funky char math on the current character. So instead of inserting a character, you are corrupting the data.
Try this instead:
#include <iostream>
#include <string>
#include <sstream>
int main(int argc, char ** argv) {
std::string a("hello\\ world");
std::stringstream ss;
for (int i = 0; i < a.length(); ++i) {
if (a[i] == '\\') {
ss << "\\\\";
}
else {
ss << a[i];
}
}
std::cout << ss.str() << std::endl;
return 0;
}
lots wrong. did not test this but it will get you closer
http://www.cplusplus.com/reference/string/string/
string stripPath(string path)
{
string newpath;
for (int i = 0; i <= path.length() ;i++)
{
if(path.at(i) == '\\')
{
newpath.append(path.at(i));
newpath.append(path.at(i));
}
else
newpath.append(path.at(i));
}
return newpath;
}
But in order for the compiler to read
backslash in i need to create a
function that will make a one
backslash into 2 backslash
The compiler only reads string when you compile, and in that case you will need two as the first back slash will be an escape character. So if you were to have a static path string in code you would have to do something like this:
std::string path = "C:\\SomeFolder\\SomeTextFile.txt";
The compiler will never actually call your function only compile it. So writing a function like this so the compiler can read a string is not going to solve your problem.
The condition if (newpath[i] = '\\') should be if (newpath[i] == '\\').
The statement newpath[i] += '\\'; will not give the intended result of concatenation. It will instead add the integral value of '\\' to newpath[i].
Moreover why are you using a char newpath[99999]; array inside the function. newpath could be std::string newpath.
int main()
{
std::string path = "c:\\test\\test2\\test3\\test4";
std::cout << "orignal path: " << path << std::endl;
size_t found = 0, next = 0;
while( (found = path.find('\\', next)) != std::string::npos )
{
path.insert(found, "\\");
next = found+4;
}
std::cout << "path with double slash: " << path << std::endl;
return 0;
}
Related
How to replace all "pi" from a string by "3.14"? Example: INPUT = "xpix" ___ OUTPUT = "x3.14x" for a string, not character array.
This doesn't work:
#include<iostream>
using namespace std;
void replacePi(string str)
{
if(str.size() <=1)
return ;
replacePi(str.substr(1));
int l = str.length();
if(str[0]=='p' && str[1]=='i')
{
for(int i=l;i>1;i--)
str[i+2] = str[i];
str[0] = '3';
str[1] = '.';
str[2] = '1';
str[3] = '4';
}
}
int main()
{
string s;
cin>>s;
replacePi(s);
cout << s << endl;
}
There is a ready to use function in the C++ lib. It is called: std::regex_replace. You can read the documentation in the CPP Reference here.
Since it uses regexes it is very powerful. The disadvantage is that it may be a little bit too slow during runtime for some uses case. But for your example, this does not matter.
So, a common C++ solution would be:
#include <iostream>
#include <string>
#include <regex>
int main() {
// The test string
std::string input{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Use simply the replace function
std::string output = std::regex_replace(input, std::regex("Pi"), "3.14");
// Show the output
std::cout << output << "\n";
}
But my guess is that you are learning C++ and the teacher gave you a task and expects a solution without using elements from the std C++ library. So, a hands on solution.
This can be implemented best with a temporary string. You check character by character from the original string. If the characters do not belong to Pi, then copy them as is to new new string. Else, copy 3.14 to the new string.
At the end, overwrite the original string with the temp string.
Example:
#include <iostream>
#include <string>
using namespace std;
void replacePi(string& str) {
// Our temporay
string temp = "";
// Sanity check
if (str.length() > 1) {
// Iterate over all chararcters in the source string
for (size_t i = 0; i < str.length() - 1; ++i) {
// Check for Pi in source string
if (str[i] == 'P' and str[i + 1] == 'i') {
// Add replacement string to temp
temp += "3.14";
// We consumed two characters, P and i, so increase index one more time
++i;
}
else {
// Take over normal character
temp += str[i];
}
}
str = temp;
}
}
// Test code
int main() {
// The test string
std::string str{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Do the replacement
replacePi(str);
// Show result
std::cout << str << '\n';
}
What you need is string::find and string::replace. Here is an example
size_t replace_all(std::string& str, std::string from, std::string to)
{
size_t count = 0;
std::string::size_type pos;
while((pos=str.find(from)) != str.npos)
{
str.replace(pos, from.length(), to);
count++;
}
return count;
}
void replacePi(std::string& str)
{
replace_all(str, "pi", "3.14");
}
I have a runtime problem with code below.
The purpose is to "recognize" the formats (%s %d etc) within the input string.
To do this, it returns an integer that matches the data type.
Then the extracted types are manipulated/handled in other functions.
I want to clarify that my purpose isn't to write formatted types in a string (snprintf etc.) but only to recognize/extract them.
The problem is the crash of my application with error:
Debug Assertion Failed!
Program:
...ers\Alex\source\repos\TestProgram\Debug\test.exe
File: minkernel\crts\ucrt\appcrt\convert\isctype.cpp
Line: 36
Expression: c >= -1 && c <= 255
My code:
#include <iostream>
#include <cstring>
enum Formats
{
TYPE_INT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_NUM
};
typedef struct Format
{
Formats Type;
char Name[5 + 1];
} SFormat;
SFormat FormatsInfo[TYPE_NUM] =
{
{TYPE_INT, "d"},
{TYPE_FLOAT, "f"},
{TYPE_STRING, "s"},
};
int GetFormatType(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return format.Type;
}
return -1;
}
bool isValidFormat(const char* formatName)
{
for (const auto& format : FormatsInfo)
{
if (strcmp(format.Name, formatName) == 0)
return true;
}
return false;
}
bool isFindFormat(const char* strBufFormat, size_t stringSize, int& typeFormat)
{
bool foundFormat = false;
std::string stringFormat = "";
for (size_t pos = 0; pos < stringSize; pos++)
{
if (!isalpha(strBufFormat[pos]))
continue;
if (!isdigit(strBufFormat[pos]))
{
stringFormat += strBufFormat[pos];
if (isValidFormat(stringFormat.c_str()))
{
typeFormat = GetFormatType(stringFormat.c_str());
foundFormat = true;
}
}
}
return foundFormat;
}
int main()
{
std::string testString = "some test string with %d arguments"; // crash application
// std::string testString = "%d some test string with arguments"; // not crash application
size_t stringSize = testString.size();
char buf[1024 + 1];
memcpy(buf, testString.c_str(), stringSize);
buf[stringSize] = '\0';
for (size_t pos = 0; pos < stringSize; pos++)
{
if (buf[pos] == '%')
{
if (buf[pos + 1] == '%')
{
pos++;
continue;
}
else
{
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
int typeFormat;
if (isFindFormat(bufFormat, stringSize, typeFormat))
{
std::cout << "type = " << typeFormat << "\n";
// ...
}
}
}
}
}
As I commented in the code, with the first string everything works. While with the second, the application crashes.
I also wanted to ask you is there a better/more performing way to recognize types "%d %s etc" within a string? (even not necessarily returning an int to recognize it).
Thanks.
Let's take a look at this else clause:
char bufFormat[1024 + 1];
memcpy(bufFormat, buf + pos, stringSize);
bufFormat[stringSize] = '\0';
The variable stringSize was initialized with the size of the original format string. Let's say it's 30 in this case.
Let's say you found the %d code at offset 20. You're going to copy 30 characters, starting at offset 20, into bufFormat. That means you're copying 20 characters past the end of the original string. You could possibly read off the end of the original buf, but that doesn't happen here because buf is large. The third line sets a NUL into the buffer at position 30, again past the end of the data, but your memcpy copied the NUL from buf into bufFormat, so that's where the string in bufFormat will end.
Now bufFormat contains the string "%d arguments." Inside isFindFormat you search for the first isalpha character. Possibly you meant isalnum here? Because we can only get to the isdigit line if the isalpha check passes, and if it's isalpha, it's not isdigit.
In any case, after isalpha passes, isdigit will definitely return false so we enter that if block. Your code will find the right type here. But, the loop doesn't terminate. Instead, it continues scanning up to stringSize characters, which is the stringSize from main, that is, the size of the original format string. But the string you're passing to isFindFormat only contains the part starting at '%'. So you're going to scan past the end of the string and read whatever's in the buffer, which will probably trigger the assertion error you're seeing.
Theres a lot more going on here. You're mixing and matching std::string and C strings; see if you can use std::string::substr instead of copying. You can use std::string::find to find characters in a string. If you have to use C strings, use strcpy instead of memcpy followed by the addition of a NUL.
You could just demand it to a regexp engine which bourned to search through strings
Since C++11 there's direct support, what you have to do is
#include <regex>
then you can match against strings using various methods, for instance regex_match which gives you the possibility, together with an smatch to find out your target with just few lines of codes using standard library
std::smatch sm;
std::regex_match ( testString.cbegin(), testString.cend(), sm, str_expr);
where str_exp is your regex to find what you want specifically
in the sm you have now every matched string against your regexp, which you can print in this way
for (int i = 0; i < sm.size(); ++i)
{
std::cout << "Match:" << sm[i] << std::endl;
}
EDIT:
to better express the result you would achieve i'll include a simple sample below
// target string to be searched against
string target_string = "simple example no.%d is: %s";
// pattern to look for
regex str_exp("(%[sd])");
// match object
smatch sm;
// iteratively search your pattern on the string, excluding parts of the string already matched
cout << "My format strings extracted:" << endl;
while (regex_search(target_string, sm, str_exp))
{
std::cout << sm[0] << std::endl;
target_string = sm.suffix();
}
you can easily add any format string you want modifying the str_exp regex expression.
I have a small program that prints out the capital form of each letter of a word, but I get the error signed/unsigned mismatch when I compile it because I'm passing a cstring as a normal string in this program. How do I pass it correctly so that I can still use text.length()? Here is the error that I get "Tester.cpp(22,23): warning C4018: '<': signed/unsigned mismatch". It's at for (int i = 0; i < text.length(); i++)
#include <iostream>
using namespace std;
string capitalizeFirstLetter(string text);
int main() {
char sentence[100];
for ( ; ; )
{
cin.getline(sentence, 100);
if (sentence != "0")
capitalizeFirstLetter(sentence);
}
return 0;
}
string capitalizeFirstLetter(string text) {
for (int i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
cout << text;
return text;
}
The simplest way to handle passing sentence as a string is to enclose it in a braced set, to provide direct initialization to the parameter std::string text eg..
for ( ; ; )
{
std::cin.getline(sentence, 100);
if (*sentence)
capitalizeFirstLetter({sentence});
}
This allows the character string sentence to be used as the Direct initialization to initialize std::string text in your capitalizeFirstLetter() function:
std::string capitalizeFirstLetter (std::string text) {
for (size_t i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
std::cout << text;
return text;
}
Your complete code, after reading Why is “using namespace std;” considered bad practice?, would then be:
#include <iostream>
std::string capitalizeFirstLetter (std::string text) {
for (size_t i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
std::cout << text;
return text;
}
int main (void) {
char sentence[100];
for ( ; ; )
{
std::cin.getline(sentence, 100);
if (*sentence)
capitalizeFirstLetter({sentence});
}
return 0;
}
(note: dereferencing sentence provides the first character which is then confirmed as something other than the nul-terminating character (ASCII 0))
A Better CapitalizeFirstLetter()
A slightly easier way to approach capitalization is to include <cctype> and an int to hold the last character read. Then the logic simply loops over each character and if the first character is an alpha-character, then capitalize it, otherwise only capitalize the letter when the current character is an alpha-character and the last character was whitespace, e.g.
std::string capitalizeFirstLetter (std::string text)
{
int last = 0
for (auto& c : text)
{
if (isalpha(c))
{
if (!i || isspace (last))
c = toupper(c);
}
last = c;
}
std::cout << text;
return text;
}
(note: the use of a range-based for loop above)
Either way works.
The error is not generating because of you passing a cstring as a normal string to the function but it is due to the fact that you are trying to compare c style string using != operator in the statement
if (sentence != "0")
capitalizeFirstLetter(sentence);
try using strcmp() for that
Several things bugging me here.
First off, don't use using namespace std, it's "ok" in this case, but don't get used to it, it can cause quite some trouble.
See Why is “using namespace std;” considered bad practice?
Next thing is, just use std::string instead of cstrings here, it's easier to write and to read and doesn't produce any measurable performance loss or something. And it's harder to produce bugs this way.
So just use
std::string sentence;
and
getline(std::cin, sentence);
And why do you handle the output inside the function that transforms your string? Just let the main print the transformed string.
So your main could look like this:
int main() {
std::string sentence;
while(true)
{
getline(std::cin, sentence);
auto capitalized = capitalizeFirstLetter(sentence);
std::cout << capitalized;
}
return 0;
}
PS: the 'error' you get is a warning, because you compare int i with text.length() which is of type size_t aka unsigned int or unsigned long int.
Problems with your code :
if (sentence != "0") : illegal comparison. If you want to break on getting 0 as input then try using strcmp (include <cstring>) as if (strcmp(sentence, "0"). (Note that strcmp returns 0 when two strings are equal.) Or simply do if (!(sentence[0] == '0' and sentence[1] == 0)). Moreover this condition should be accompanied with else break; to prevent the for loop from running forever.
for (int i = 0; i < text.length(); i++) : generates warning because of comparison between signed and unsigned types. Change data-type of i to string::size_type to prevent the warning.
<string> (for std::string) and <cctype> (for std::toupper) were not included.
Thanks to #john for pointing this out. Your code has undefined behaviour if last character of a string is a space. Add a check if i is still less than text.length() or not before using text[i].
Another case of error is when an space is there after 0. Move getline to condition of for to fix this. Now there will be no need to input a 0 to terminate program. Moreover, I recommend using while loop for this instead of for.
You may also need to print a newline to separate sentences. Moreover, I would prefer printing the modified sentence in the main() function using the returned string from capitalizeFirstLetter.
It doesn't matter much in short (beginner-level) codes, but avoid acquiring the habit of putting using namespace std; on the top of every code you write. Refer this.
Fixed code :
#include <cctype>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
string capitalizeFirstLetter(string text);
int main() {
char sentence[100];
while (cin.getline(sentence, 100))
cout << capitalizeFirstLetter(sentence) << '\n';
}
string capitalizeFirstLetter(string text) {
for (string::size_type i = 0; i < text.length(); i++) {
if (i == 0)
text[i] = toupper(text[i]);
if (text[i] == ' ')
if (++i < text.length())
text[i] = toupper(text[i]);
}
return text;
}
Sample Run :
Input :
hello world
foo bar
Output :
Hello World
Foo Bar
My Version (Requires C++20) :
#include <cctype>
#include <iostream>
#include <string>
auto capitalizeFirstLetter(std::string text) {
for (bool newWord = true; auto &&i : text) {
i = newWord ? std::toupper(i) : i;
newWord = std::isspace(i);
}
return text;
}
int main() {
std::string sentence;
while (std::getline(std::cin, sentence))
std::cout << capitalizeFirstLetter(sentence) << std::endl;
}
Sample Run
I did get the next character on a string (hello-->ifmmp) but in the case of hello* i want to be able to still display the * as the exception, it can be also a number but i guess it does not matter because is not in the alphabet.
this is my code, Where should be the else if?
There is another option but i dont find it optimized, it is to add inside the first for loop this:
string other="123456789!##$%^&*()";
for(int z=0;z<other.length();z++)
{
if(str[i]==other[z])
str2+=other[z];
}
Then this is the main code;
int main()
{
string str = "hello*";
string str2="";
string alphabet = "abcdefghijklmnopqrstuvwxyz";
for(int i=0;i<str.length();i++)
{
for(int j=0;j<alphabet.length();j++)
{
if(str[i]==alphabet[j])
{
str2+=alphabet[j+1];
}
}
}
cout<<str2<<endl;
return 0;
}
I like functions. They solve a lot of problems. For example, if you take the code you already have, paste it into a function, and give it a little tweak
char findreplacement(char ch, const std::string & alphabet)
{
for (int j = 0; j < alphabet.length(); j++)
{
if (ch == alphabet[j])
{
return alphabet[(j+1) % alphabet.length()];
// return the replacement character
// using modulo, %, to handle wrap around z->a
}
}
return ch; // found no replacement. Return original character.
}
you can call the function
for (int i = 0; i < str.length(); i++)
{
str2 += findreplacement(str[i], alphabet);
}
to build str2. Consider using a range-based for here:
for (char ch: str)
{
str2 += findreplacement(ch, alphabet);
}
It's cleaner and a lot harder to screw up.
There is a function isalpha in the standard library which is very useful for classification.
You could do something like this.
(This kind of exercise usually assumes the ASCII encoding of the English alphabet, and this is a very ASCII-specific solution. If you want a different alphabet or a different character encoding, you need to handle that yourself.)
#include <cctype>
#include <string>
#include <iostream>
int main()
{
std::string str = "Hello*Zzz?";
std::string str2;
for (char c: str)
{
if (std::isalpha(c))
{
c += 1;
if (!std::isalpha(c))
{
// Went too far; wrap around to 'a' or 'A'.
c -= 26;
}
}
str2 += c;
}
std::cout << str2 << std::endl;
}
Output:
Ifmmp*Aaa?
I need to make a program that capitalizes the first character of each sentence in a string. For instance, if the string argument is “hello. my name is Joe. what is your name?” the function should manipulate the string so it contains “Hello. My name is Joe. What is your name?” I'm not sure what I am doing wrong. Any suggestions? Here is my code:
#include<iostream>
#include<cctype>
#include<cstdlib>
using namespace std;
void capitalize(char sentence[], int const SIZE);
int main()
{
const int SIZE = 1024;
char sentence[SIZE];
cout << "Enter a string: " << endl << endl;
cin.getline(sentence, SIZE);
capitalize(sentence, SIZE);
system("pause");
return(0);
}
void capitalize(char sentence[], int SIZE)
{
char *strPtr;
int count = 0;
sentence[0] = toupper(sentence[0]);
for (int i = 0; i < SIZE; i++)
{
strPtr = strstr(sentence[i], ".");
if (*strPtr == '.')
{
*strPtr = toupper(*strPtr);
}
}
while (sentence[count] != '\0')
{
cout << sentence[count];
count++;
}
}
#include <cstring> // need this for strstr()
void capitalize(char sentence[], int SIZE)
{
char *strPtr;
int count = 0;
sentence[0] = toupper(sentence[0]);
for (int i = 0; i < SIZE; i++)
{
strPtr = strstr(&sentence[i], ".");
//strPtr returns the pointer to
//the first occurence of "." after sentence[i]
if(strPtr==NULL) break;
if (*strPtr == '.')
{
// you really dont want to do this
//*strPtr = toupper(*strPtr);
// put the suitable code here and everything will work
}
}
//why the while loop? and count?
while (sentence[count] != '\0')
{
cout << sentence[count];
count++;
}
}
What you were doing was to capitalize "." but clearly you want the next character to be capitalized. So write that part of code yourself as you'll find it more rewarding.
First, as mentioned in the comments, you're not including cstring. Second, you're calling strstr on sentence[i], which is a char. You want sentence + i which is a char*. That'll fix your syntax errors.
For logical error, it looks like you're trying toupper the period.
strPtr = strstr(sentence[i], "."); should find the first period in the string starting at i (inclusive). Then you check if strstr found anything (if not it would return null. If it's found the sequence you uppercase strPtr, but strPtr still points at the first character of the target string, that is '.'. You should be looking for the target string ". " then incrementing one past that to find the first letter of the next sentence. Unfortunately there's no safe way of doing that with strstr since it doesn't tell you how far into the string it looked, so it's possible the string simply ends with ". " and one past that falls off the array. You're either going to need to iterate through the array manually, looking for '.' then checking past that, or use std::find instead.