For example if I have something like :
word="Bag"
I need output as:
B-2
a-1
g-7
Here is a more portable solution:
There are only 26 letters to consider, thus your question is easily answerable by simply providing a lookup table. There is no need to call functions such as tolower, or to assume that letters are contiguous in the collating sequence (as EBCDIC does not follow this pattern):
#include <iostream>
#include <unordered_map>
#include <string>
int main()
{
// Create the lookup table -- this could have been done in many ways,
// such as a static table of characters to values, but I chose a simple
// literal string and build the table at runtime.
const char *alpha = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
std::unordered_map<char, int> cMap;
for (int i = 0; i < 52; ++i)
cMap[alpha[i]] = i / 2; // Note there are two characters per character value,
// the lower and the upper case version of the character
// Test
std::string test = "Bag";
for ( auto& c : test)
std::cout << c << '-' << cMap[c]+1 << ' ';
std::cout << '\n';
test = "Buy";
for ( auto& c : test)
std::cout << c << '-' << cMap[c]+1 << ' ';
std::cout << '\n';
test = "Elephant";
for ( auto& c : test)
std::cout << c << '-' << cMap[c]+1 << ' ';
}
Output:
B-2 a-1 g-7
B-2 u-21 y-25
E-5 l-12 e-5 p-16 h-8 a-1 n-14 t-20
for (char ch: word) {
cout << ch << "-" << (tolower(ch) - 'a' + 1) << " ";
}
I hope the below code snippet helps :
char c = 'g'; //your character here
int position = 1 + (tolower(c))-'a': //ensure that character is in lowercase and find its position relative to 'a'
I tried
char c='A';
cout<<(int)c;
But this is not for special characters and numbers I think. What's should I do?
This will kinda do it:
#include <iostream>
int main()
{
char c = 0;
for (int i = 0; i < 128; ++i,++c)
std::cout << c << " = " << i << std::endl;
// or: std::cout << c << " = " << static_cast<int>(c) << std::endl;
}
But really, it is easier (and better) to just go look at http://www.asciitable.com/ or a similar site, because everything below 32 is not printable.
Also note, only the first 127 characters are ASCII - above that we run into extended ASCII that depends on your console settings.
I was just reviewing my C++. I tried to do this:
#include <iostream>
using std::cout;
using std::endl;
void printStuff(int x);
int main() {
printStuff(10);
return 0;
}
void printStuff(int x) {
cout << "My favorite number is " + x << endl;
}
The problem happens in the printStuff function. When I run it, the first 10 characters from "My favorite number is ", is omitted from the output. The output is "e number is ". The number does not even show up.
The way to fix this is to do
void printStuff(int x) {
cout << "My favorite number is " << x << endl;
}
I am wondering what the computer/compiler is doing behind the scenes.
The + overloaded operator in this case is not concatenating any string since x is an integer. The output is moved by rvalue times in this case. So the first 10 characters are not printed. Check this reference.
if you will write
cout << "My favorite number is " + std::to_string(x) << endl;
it will work
It's simple pointer arithmetic. The string literal is an array or chars and will be presented as a pointer. You add 10 to the pointer telling you want to output starting from the 11th character.
There is no + operator that would convert a number into a string and concatenate it to a char array.
adding or incrementing a string doesn't increment the value it contains but it's address:
it's not problem of msvc 2015 or cout but instead it's moving in memory back/forward:
to prove to you that cout is innocent:
#include <iostream>
using std::cout;
using std::endl;
int main()
{
char* str = "My favorite number is ";
int a = 10;
for(int i(0); i < strlen(str); i++)
std::cout << str + i << std::endl;
char* ptrTxt = "Hello";
while(strlen(ptrTxt++))
std::cout << ptrTxt << std::endl;
// proving that cout is innocent:
char* str2 = str + 10; // copying from element 10 to the end of str to stre. like strncpy()
std::cout << str2 << std::endl; // cout prints what is exactly in str2
return 0;
}
I'm working on an assignment where I need to print out the ASCII table in the table format exactly like the picture below.
http://i.gyazo.com/f1a8625aad1d55585df20f4dba920830.png
I currently can't get the special words/symbols to display (8, 9, 10, 13, 27, 32, 127).
Here it is running:
http://i.gyazo.com/80c8ad48ef2993e93ef9b8feb30e53af.png
Here is my current code:
#include <iomanip>
#include <iostream>
using namespace std;
int main()
{
cout<<"ASCII TABLE:"<<endl;
cout<<endl;
for (int i = 0; i < 128; i++)
{
if (i <= 32)
cout << "|" << setw(2)
<<i
<< setw(3)
<< "^" << char (64+i) <<"|";
if (i >= 33)
cout << "|" << setw(3)
<<i
<< setw(3)
<<char (i) << "|";
if((i+1)%8 == 0) cout << endl;
}
return 0;
}
8 Back Space
9 Horizontal Tab
10 New Line
13 carriage return
27 Escape (Esc)
32 Space
127 Del
As Above these ASCII characters doesn't display any visible or printed character. That's why you might be thinking you are not getting these values.
I'm no sure what's your real problem there, but you didn't get an answer yet about how to print the special codes.
Running your programme I see that you have some minor alignment problems. If that's the problem, note that setw(3) only applies to the next element:
cout << setw(3) << "^" << char (64+i); // prints " ^A" instead of " ^A".
If you try to correct into
cout << setw(3) << "^"+ char (64+i); // ouch !!!!
you'll get undefined behaviour (garbage) because "^" is a pointer to a string and adding char(64+i) is understood as adding an offset of 64+i to this pointer. As this is a rather random address, you'll get garbage. Use a std::string instead.
The other difference I see between your programme's output and the expected result is that you don't print the code of the special chars. If that's the problem, either use a switch statement (very repetitive here), or a lot of if/else or use an associative map.
Here an alternative proposal putting all this together:
map<char, string>special{ { 8, "BS " }, { 9, "\\t " }, { 10, "\\n " }, { 13, "CR " }, { 27, "ESC" }, { 32, "SP " }, { 127, "DEL" } };
cout << "ASCII TABLE:" << endl << endl;
for (int i = 0; i < 128; i++) {
cout << "|" << setw(3)<<i<<setw(4); // setw() only applies to next
if (iscntrl(i) || isspace(i)) { // if its a control char or a space
auto it = special.find(i); // look if there's a special translation
if (it != special.end()) // if yes, use it
cout << it->second;
else cout << string("^") + char(64 + i)+ string(" "); // if not, ^x, using strings
}
else if (isprint(i)) // Sorry I'm paranoïd: but I always imagine that there could be a non printable ctrl ;-)
cout << char(i)+string(" ") ; // print normal char
cout << "|";
if ((i + 1) % 8 == 0) cout << endl;
}
Now some additional advices:
take the effort to indent
instead of manual categorization of chars, use iscntrl(), isspace(), isprint(). As long as you only use ascii, it's manageable to do like you did. But as soons as you move to internationalisation and wide chars it becomes increasinlgy cumbersome to do that whereas there are easy wide equivalents like iswcntrl(), iswspace(), iswprint().
also be rigorous on two consecutive if: If you know that only one of the two should apply, make the effort to write if ... else if these four additional lettes can save you hours of debugging later.
This question already has answers here:
How do you search a std::string for a substring in C++?
(6 answers)
Closed 8 years ago.
I have a client for a pre-existing server. Let's say I get some packets "MC123, 456!##".
I store these packets in a char called message. To print out a specific part of them, in this case the numbers part of them, I would do something like "cout << message.substr(3, 7) << endl;".
But what if I receive another message "MC123, 456, 789!##". "cout << message.substr(3,7)" would only print out "123, 456", whereas I want "123, 456, 789". How would I do this assuming I know that every message ends with "!##".
First - Sketch out the indexing.
std::string packet1 = "MC123, 456!##";
// 0123456789012345678
// ^------^ desired text
std::string packet2 = "MC123, 456, 789!##";
// 0123456789012345678
// ^-----------^ desired text
The others answers are ok. If you wish to use std::string find,
consider rfind and find_first_not_of, as in the following code:
// forward
void messageShow(std::string packet,
size_t startIndx = 2);
// /////////////////////////////////////////////////////////////////////////////
int main (int, char** )
{
// 012345678901234567
// |
messageShow("MC123, 456!##");
messageShow("MC123, 456, 789!##");
messageShow("MC123, 456, 789, 987, 654!##");
// error test cases
messageShow("MC123, 456, 789##!"); // missing !##
messageShow("MC123x 456, 789!##"); // extraneous char in packet
return(0);
}
void messageShow(std::string packet,
size_t startIndx) // default value 2
{
static size_t seq = 0;
seq += 1;
std::cout << packet.size() << " packet" << seq << ": '"
<< packet << "'" << std::endl;
do
{
size_t bangAtPound_Indx = packet.rfind("!##");
if(bangAtPound_Indx == std::string::npos){ // not found, can't do anything more
std::cerr << " '!##' not found in packet " << seq << std::endl;
break;
}
size_t printLength = bangAtPound_Indx - startIndx;
const std::string DIGIT_SPACE = "0123456789, ";
size_t allDigitSpace = packet.find_first_not_of(DIGIT_SPACE, startIndx);
if(allDigitSpace != bangAtPound_Indx) {
std::cerr << " extraneous char found in packet " << seq << std::endl;
break; // something extraneous in string
}
std::cout << bangAtPound_Indx << " message" << seq << ": '"
<< packet.substr(startIndx, printLength) << "'" << std::endl;
}while(0);
std::cout << std::endl;
}
This outputs
13 packet1: 'MC123, 456!##'
10 message1: '123, 456'
18 packet2: 'MC123, 456, 789!##'
15 message2: '123, 456, 789'
28 packet3: 'MC123, 456, 789, 987, 654!##'
25 message3: '123, 456, 789, 987, 654'
18 packet4: 'MC123, 456, 789##!'
'!##' not found in packet 4
18 packet5: 'MC123x 456, 789!##'
extraneous char found in packet 5
Note: String indexes start at 0. The index of the digit '1' is 2.
The correct approach is to look for existence / location of the "known termination" string, then take the substring up to (but not including) that substring.
Something like
str::string termination = "!#$";
std::size_t position = inputstring.find(termination);
std::string importantBit = message.substr(0, position);
You could check the front of the string separately as well. Combining these, you could use regular expressions to make your code more robust, using a regex like
MC([0-9,]+)!#\$
This will return the bit between MC and !#$ but only if it consists entirely of numbers and commas. Obviously you can adapt this as needed.
UPDATE you asked in your comment how to use the regular expression. Here is a very simple program. Note - this is using C++11: you need to make sure our compiler supports it.
#include <iostream>
#include <regex>
int main(void) {
std::string s ("ABC123,456,789!#$");
std::smatch m;
std::regex e ("ABC([0-9,]+)!#\\$"); // matches the kind of pattern you are looking for
if (std::regex_search (s,m,e)) {
std::cout << "match[0] = " << m[0] << std::endl;
std::cout << "match[1] = " << m[1] << std::endl;
}
}
On my Mac, I can compile the above program with
clang++ -std=c++0x -stdlib=libc++ match.cpp -o match
If instead of just digits and commas you want "anything" in your expression (but it's still got fixed characters in front and behind) you can simply do
std::regex e ("ABC(.*)!#\\$");
Here, .+ means "zero or more of 'anything'" - but followed by !#$. The double backslash has to be there to "escape" the dollar sign, which has special meaning in regular expressions (it means "the end of the string").
The more accurately your regular expression reflects exactly what you expect, the better you will be able to trap any errors. This is usually a very good thing in programming. "Always check your inputs".
One more thing - I just noticed you mentioned that you might have "more stuff" in your string. This is where using regular expressions quickly becomes the best. You mentioned a string
MC123, 456!##*USRChester.
and wanted to extract 123, 456 and Chester. That is - stuff between MC and !#$, and more stuff after USR (if that is even there). Here is the code that shows how that is done:
#include <iostream>
#include <regex>
int main(void) {
std::string s1 ("MC123, 456!#$");
std::string s2 ("MC123, 456!#$USRChester");
std::smatch m;
std::regex e ("MC([0-9, ]+)!#\\$(?:USR)?(.*)$"); // matches the kind of pattern you are looking for
if (std::regex_search (s1,m,e)) {
std::cout << "match[0] = " << m[0] << std::endl;
std::cout << "match[1] = " << m[1] << std::endl;
std::cout << "match[2] = " << m[2] << std::endl;
}
if (std::regex_search (s2,m,e)) {
std::cout << "match[0] = " << m[0] << std::endl;
std::cout << "match[1] = " << m[1] << std::endl;
std::cout << "match[2] = " << m[2] << std::endl;
if (match[2].length() > 0) {
std::cout << m[2] << ": " << m[1] << std::endl;
}
}
}
Output:
match[0] = MC123, 456!#$
match[1] = 123, 456
match[2] =
match[0] = MC123, 456!#$USRChester
match[1] = 123, 456
match[2] = Chester
Chester: 123, 456
The matches are:
match[0] : "everything in the input string that was consumed by the Regex"
match[1] : "the thing in the first set of parentheses"
match[2] : "The thing in the second set of parentheses"
Note the use of the slightly tricky (?:USR)? expression. This says "This might (that's the ()? ) be followed by the characters USR. If it is, skip them (that's the ?: part) and match what follows.
As you can see, simply testing whether m[2] is empty will tell you whether you have just numbers, or number plus "the thing after the USR". I hope this gives you an inkling of the power of regular expressions for chomping through strings like yours.
If you are sure about the ending of the message, message.substr(3, message.size()-6) will do the trick.
However, it is good practice to check everything, just to avoid surprises.
Something like this:
if (message.size() < 6)
throw error;
if (message.substr(0,3) != "MCX") //the exact numbers do not match in your example, but you get the point...
throw error;
if (message.substr(message.size()-3) != "!##")
throw error;
string data = message.substr(3, message.size()-6);
Just calculate the offset first.
string str = ...;
size_t start = 3;
size_t end = str.find("!##");
assert(end != string::npos);
return str.substr(start, end - start);
You can get the index of "!##" by using:
message.find("!##")
Then use that answer instead of 7. You should also check for it equalling std::string::npos which indicates that the substring was not found, and take some different action.
string msg = "MC4,512,541,3123!##";
for (int i = 2; i < msg.length() - 3; i++) {
if (msg[i] != '!' && msg[i + 1] != '#' && msg[i + 2] != '#')
cout << msg[i];
}
or use char[]
char msg[] = "MC4,123,54!##";
sizeof(msg -1 ); //instead of msg.length()
// -1 for the null byte at the end (each char takes 1 byte so the size -1 == number of chars)