Manipulating the standard output stream to print multiline strings horizontally - c++

So I have three strings and these strings are supposed to occupy 3 lines. I thought this was a good way to represent my string:
std::string str1 = "███████\n███1███\n███████";
std::string str2 = "███████\n███2███\n███████";
std::string str3 = "███████\n███3███\n███████";
But I realise that when I do this and just cout the strings, they get printed on top of each other which is not I want. I want the output to look like this:
█████████████████████
███1██████2██████3███
█████████████████████
How can I achieve this effect? I only know setw to manipulate the output however I don't know how that could help here.
note: I will have these stored in an array and than loop over the array and print them, I feel like that might change the solution a bit as well.

Store the rows of each card as elements in an array. That makes it pretty easy.
#include <iostream>
int main()
{
const char * str1[3] = {"███████","███1███","███████"};
const char * str2[3] = {"███████","███2███","███████"};
const char * str3[3] = {"███████","███3███","███████"};
for( int row = 0; row < 3; row ++ )
{
std::cout << str1[row] << str2[row] << str3[row] << "\n";
}
}
Output:
█████████████████████
███1██████2██████3███
█████████████████████
Again, pretty easy to add a space between those, if you want.

You could split each on \n and print them. We can use std::stringstream for splitting by \n.
void print(std::array<std::string, 3>& arr){
std::vector<std::stringstream> arr_buf{};
arr_buf.reserve(arr.size());
for(auto& str: arr){
arr_buf.emplace_back(str);
}
for(auto i=0u; i < arr.size(); ++i){
for(auto& stream: arr_buf){
std::string t;
stream >> t;
std::cout << t ;
}
std::cout << "\n";
}
}
Output:
print(arr)
█████████████████████
███1██████2██████3███
█████████████████████
Link to Demo

If you are certain that your output will always be displayed on a modern terminal supporting “ANSI Escape Codes” then you can use that to your advantage.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
// helper: split a string into a list of views
auto splitv( const std::string & s, const std::string & separators )
{
std::vector <std::string_view> views;
std::string::size_type a = 0, b = 0;
while (true)
{
a = s.find_first_not_of( separators, b );
b = s.find_first_of ( separators, a );
if (a >= s.size()) break;
if (b == s.npos) b = s.size();
views.emplace_back( &(s[a]), b-a );
}
return views;
}
std::string print( const std::string & s )
{
std::ostringstream os;
for (auto sv : splitv( s, "\n" ))
os
<< "\033" "7" // DEC save cursor position
<< sv
<< "\033" "8" // DEC restore cursor position
<< "\033[B"; // move cursor one line down
return os.str().substr( 0, os.str().size()-5 );
}
std::string movexy( int dx, int dy )
{
std::ostringstream os;
if (dy < 0) os << "\033[" << -dy << "A";
else if (dy > 0) os << "\033[" << dy << "B";
if (dx > 0) os << "\033[" << dx << "C";
else if (dx < 0) os << "\033[" << -dx << "D";
return os.str();
}
int main()
{
std::string str1 = "███████\n███1███\n███████";
std::string str2 = "███████\n███2███\n███████";
std::string str3 = "███████\n███3███\n███████";
std::cout
<< "\n" "\n\n" // blank line at top + blocks are three lines high
<< movexy( 2, -2 ) << print( str1 ) // first block is placed two spaces from left edge
<< movexy( 1, -2 ) << print( str2 ) // remaining blocks are placed one space apart
<< movexy( 1, -2 ) << print( str3 )
<< "\n\n"; // newline after last block, plus extra blank line at bottom
}
This produces the output:
███████ ███████ ███████
███1███ ███2███ ███3███
███████ ███████ ███████
The addition of spacing is, of course, entirely optional and only added for demonstrative purposes.
Advantages: UTF-8 and Pretty colors!
The advantage to this method is that you do not have to store or otherwise take any special care for strings containing multi-byte characters (UTF-8, as yours does) or any additional information like terminal color sequences.
That is, you could color each of your blocks differently by adding a color sequence to each strN variable! (The caveat is that you must repeat a color sequence after every newline. This is a known problem with various terminals...)
// red, white, and blue
std::string str1 = "\033[31m███████\n\033[31m███1███\n\033[31m███████";
std::string str2 = "\033[37m███████\n\033[37m███2███\n\033[37m███████";
std::string str3 = "\033[34m███████\n\033[34m███3███\n\033[34m███████";
Relative vs Absolute Caret Positioning
The other caveat to this particular example is that you must be aware of where the text caret (“cursor”) ends-up after each output. You could also use terminal escape sequences to absolutely position the caret before every output.
std::string gotoxy( int x, int y )
{
std::ostringstream os;
os << "\033[" << y << ";" << x << "H";
return os.str();
}
Then you wouldn’t have to care where the caret ends up. Just specify an absolute position before printing. Just don’t let the text scroll!
Windows OS Considerations
Finally, if you are on Windows and using the old Windows Console, you must initialize the terminal for ANSI terminal sequences and for UTF-8 output:
#ifdef _WIN32
#include <windows.h>
void init_terminal()
{
DWORD mode;
HANDLE hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleMode( hStdOut, &mode );
SetConsoleMode( hStdOut, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING );
SetConsoleOutputCP( 65001 );
}
#else
void init_terminal() { }
#endif
int main()
{
init_terminal();
...
This does no harm to the new Windows Terminal. I recommend you do it either way just because you do not know which of the two your user will use to run your program, alas.

Related

How do I delete a line text which has already been written on the terminal in c++?

I am currently making a Self Service Order Payment Program for a project and I was trying to figure out a way to erase the previous line of text to make it look cleaner. I discovered there was a similar function to system("CLS"); but instead of erasing all the text in the console, it only erases certain parts of the text.
I've been coding for about a week or two so if I missed anything please tell me.
switch(buy){
case '1':
//random code
break;
default:
cout << "sorry thats not a valid number ;w;\n\n"; //remove this text after system("pause")
system("pause");
system("CLS"); //I need this to remove only one line instead of the whole thing.
break;
}
The \ns at the end of this line makes it hard to remove the text on the line using only standard control characters:
cout << "sorry thats not a valid number ;w;\n\n";
Also, the system("pause"); is non-standard and will likely also result in a newline (I'm not sure about that).
What you could do is to skip the printing of \n and to just sleep a little before continuing.
Example:
#include <chrono> // misc. clocks
#include <iostream>
#include <string>
#include <thread> // std::this_thread::sleep_for
// a function to print some text, sleep for awhile and then remove the text
void print_and_clear(const std::string& txt, std::chrono::nanoseconds sleep) {
std::cout << txt << std::flush; // print the text
std::this_thread::sleep_for(sleep); // sleep for awhile
// Remove the text by returning to the beginning of the line and
// print a number of space characters equal to the length of the
// text and then return to the beginning of the line again.
std::cout << '\r' << std::string(txt.size(), ' ') << '\r' << std::flush;
}
int main() {
print_and_clear("sorry thats not a valid number...", std::chrono::seconds(1));
std::cout << "Hello\n";
}
The above will print your text, sleep for a second, then remove the text and continue. What's left on the screen after the program has executed is only Hello.
you need to declare a variable and then use if condition.
i don`t know c++ but i give to hint here.
bool systempaused=false;
later on
if(!systempaused)
{
//print your line
}
system("pause")
You can do:-
cout<<"\r lots of spaces "<<endl;
basically what \r escape sequence does is that it brings the cursor to the start of the line. If you print anything after printing \r it will overwrite what was already on that line
As I know there are no standard C++ only solutions for your task, there are platform-dependend ways that I'll describe below.
Main thing needed to achieve your task is to move cursor one line up. Afterwards you can just print spaces to clear line (and move cursor to start of line through \r).
I provide two next variants (Variant 1 and Variant 2) of solving your task.
Variant 1. Using ANSI escape codes (Windows/Linux/MacOS).
There are so-called ANSI escaped codes that allow you to do rich manipulations of console. Including your task (moving cursor one line up).
Through this escape codes moving line up is achieved by printing string "\x1b[1A" to console (to move e.g. 23 lines up you may print "\x1b[23A", see 23 inside this string). Also you may want to move cursor to right, this is achieved through "\x1b[23C" (to move 23 positions to right).
By default Linux/MacOS and other POSIX systems usually support ANSI escape codes (different terminal implementations may or may not support them). Windows also supports ANSI escape codes but they are not enabled by default, it needs to be enabled by special WinAPI functions.
Inside ClearLines() function don't forget to tweak width argument, it is set to 40 right now, it signifies width of your console, precisely it clears only first width chars of line with spaces.
Next code does what you need for Windows and Unix systems. Windows-specific code is located between #ifdef and #endif.
Try it online!
#include <iostream>
#include <cstdlib>
#ifdef _WIN32
#include <windows.h>
inline bool WinAnsiConsoleEnable(int stdout_or_stderr = 0) {
if (!SetConsoleOutputCP(65001)) // Enable UTF-8 console if needed.
return false;
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
DWORD outMode = 0;
HANDLE stdoutHandle = GetStdHandle(stdout_or_stderr == 0 ?
STD_OUTPUT_HANDLE : stdout_or_stderr == 1 ? STD_ERROR_HANDLE : 0);
if (stdoutHandle == INVALID_HANDLE_VALUE)
return false;
if (!GetConsoleMode(stdoutHandle, &outMode))
return false;
// Enable ANSI escape codes
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
if (!SetConsoleMode(stdoutHandle, outMode))
return false;
return true;
}
#endif // _WIN32
static void ClearLines(size_t cnt, size_t width = 40) { // Clears cnt last lines.
std::cout << "\r";
for (size_t i = 0; i < cnt; ++i) {
for (size_t j = 0; j < width; ++j)
std::cout << " ";
std::cout << "\r";
if (i + 1 < cnt)
std::cout << "\x1b[1A"; // Move cursor one line up, ANSI sequence.
}
}
int main() {
#ifdef _WIN32
if (!WinAnsiConsoleEnable()) {
std::cout << "Error enabling Win ansi console!" << std::endl;
return -1;
}
#endif
bool good = false;
char buy = 0;
std::cout << "Enter number:" << std::endl;
while (!good) {
std::cin >> buy;
switch (buy) {
case '1': {
std::cout << "Valid number." << std::endl;
good = true;
break;
}
default: {
std::cout << "Sorry thats not a valid number!\n";
#ifdef _WIN32
std::system("pause");
#else
std::system("read -p \"Press enter to continue . . . \" x");
#endif
ClearLines(4);
break;
}
}
}
}
Output (shown on Linux, Windows is same) (+ ascii-video):
Variant 2. Using WinAPI functions (Windows-only).
Next variant works only for windows and uses only WinAPI console manipulation functions (no ANSI escapes).
#include <iostream>
#include <cstdlib>
#include <windows.h>
// Moves cursor by (DeltaX, DeltaY) = (offx, offy) relative to current position.
inline bool WinMoveCursor(int offx, int offy) {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO cbsi = {};
if (!GetConsoleScreenBufferInfo(hConsole, &cbsi))
return false;
COORD coord = cbsi.dwCursorPosition;
coord.X += offx;
coord.Y += offy;
if (!SetConsoleCursorPosition(hConsole, coord))
return false;
return true;
}
static void ClearLines(size_t cnt, size_t width = 40) { // Clears cnt last lines.
std::cout << "\r";
for (size_t i = 0; i < cnt; ++i) {
for (size_t j = 0; j < width; ++j)
std::cout << " ";
std::cout << "\r";
if (i + 1 < cnt)
WinMoveCursor(0, -1); // Move cursor one line up, WinAPI.
}
}
int main() {
SetConsoleOutputCP(65001); // Enable UTF-8 if needed.
bool good = false;
char buy = 0;
std::cout << "Enter number:" << std::endl;
while (!good) {
std::cin >> buy;
switch (buy) {
case '1': {
std::cout << "Valid number." << std::endl;
good = true;
break;
}
default: {
std::cout << "Sorry thats not a valid number!\n";
std::system("pause");
ClearLines(4);
break;
}
}
}
}

Function behaves differently when run on Windows or Linux

I have a simple function that prints lines of text to the console, centered, with empty space filled in with an '=' sign. When I run this function with my program on Linux I see the text displayed properly at the top of the console window followed by the menu prompt from my program, but on Windows it prints nothing and skips directly to the menu prompt. Both programs are compiled and run in codeblocks using GNU gcc with -std=c++11.
void _print_center(vector<string>& tocenter)
{
int center;
for ( int x; x<static_cast<int>(tocenter.size());x++ )
{
char sfill = '=';
string line = tocenter[x];
center = (68/2)-(tocenter[x].length()/2);
line.replace(0, 0, center, sfill);
cout << std::left << std::setfill(sfill);
cout << std::setw(68) << line << endl;
}
}
You got an answer to your question (uninitialized variables). I recommend that you untangle and simplify your code so that this kind of issues don't creep up as often. For example:
Create a function that centers a single string.
void center( std::ostream& os, const std::string& text, int width ) {
if ( text.size() >= width ) {
// Nothing to center, just print the text.
os << text << std::endl;
} else {
// Total whitespace to pad.
auto to_pad = width - text.size();
// Pad half on the left
auto left_padding = to_pad / 2;
// And half on the right (account for uneven numbers)
auto right_padding = to_pad - left_padding;
// Print the concatenated strings. The string constructor will
// correctly handle a padding of zero (it will print zero `=`).
os << std::string( left_padding, '=' )
<< text
<< std::string( right_padding, '=' )
<< std::endl;
}
}
Once you've tested that the function works well for a single string, it is trivial to rely on C++ to apply it to a vector of strings:
void center( std::ostream& os,
const std::vector< std::string >& strings,
int width ) {
for ( auto&& string : strings ) {
center( os, string, width );
}
}
Whether you want to use std::string, or iomanip manipulators, or std::setfill the point remains the same: do not implement "iteration and formating" in the same function.

C++: Separating a char* with '\t' delimiter

I've been fighting this problem for a while now, and can't seem to find a simple solution that doesn't involve parsing a char * by hand. I need to split my char* variable by '\t', and I've tried the following ways:
Method 1:
char *splitentry;
std::string ss;
splitentry = strtok(read_msg_.data(), "\\t");
while(splitentry != NULL)
{
std::cout << splitentry << std::endl;
splitentry = strtok(NULL, "\\t");
}
Using the input '\tthis\tis\ta\ttest'
results in this output:
his
is
a
es
Method 2:
std::string s(read_msg_.data());
boost::algorithm::split(strs, s, boost::is_any_of("\\t");
for (int i = 0; i < strs.size(); i++)
std::cout << strs.at(i) << std::endl;
Which creates an identical output.
I've tried using boost::split_regex and used "\\t" as my regex value, but nothing gets split. Will I have to split it on my own, or am I going about this incorrectly?
I would try to make things a little simpler by sticking to std:: functions. (p.s. you never use this: std::string ss;)
Why not do something like this?
Method 1: std::istringstream
std::istringstream ss(read_msg_.data());
std::string line;
while( std::getline(ss,line,ss.widen('\t')) )
std::cout << line << std::endl;
Method 2: std::string::substr (my preferred method as it is lighter)
std::string data(read_msg_.data());
std::size_t SPLITSTART(0); // signifies the start of the cell
std::size_t SPLITEND(0); // signifies the end of the cell
while( SPLITEND != std::string::npos ) {
SPLITEND = data.find('\t',SPLITSTART);
// SPLITEND-SPLITSTART signifies the size of the string
std::cout << data.substr(SPLITSTART,SPLITEND-SPLITSTART) << std::endl;
SPLITSTART = SPLITEND+1;
}

C++ How to create byte[] array from file (I don't mean reading file byte by byte)?

I have a problem I neither can solve on my own nor find answer anywhere. I have a file contains such a string:
01000000d08c9ddf0115d1118c7a00c04
I would like to read the file in the way, that I would do manually like that:
char fromFile[] =
"\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x011\x5d\x11\x18\xc7\xa0\x0c\x04";
I would really appreciate any help.
I want to do it in C++ (the best would be vc++).
Thank You!
int t194(void)
{
// imagine you have n pair of char, for simplicity,
// here n is 3 (you should recognize them)
char pair1[] = "01"; // note:
char pair2[] = "8c"; // initialize with 3 char c-style strings
char pair3[] = "c7"; //
{
// let us put these into a ram based stream, with spaces
std::stringstream ss;
ss << pair1 << " " << pair2 << " " << pair3;
// each pair can now be extracted into
// pre-declared int vars
int i1 = 0;
int i2 = 0;
int i3 = 0;
// use formatted extractor to convert
ss >> i1 >> i2 >> i3;
// show what happened (for debug only)
std::cout << "Confirm1:" << std::endl;
std::cout << "i1: " << i1 << std::endl;
std::cout << "i2: " << i2 << std::endl;
std::cout << "i3: " << i3 << std::endl << std::endl;
// output is:
// Confirm1:
// i1: 1
// i2: 8
// i3: 0
// Shucks, not correct.
// We know the default radix is base 10
// I hope you can see that the input radix is wrong,
// because c is not a decimal digit,
// the i2 and i3 conversions stops before the 'c'
}
// pre-delcare
int i1 = 0;
int i2 = 0;
int i3 = 0;
{
// so we try again, with radix info added
std::stringstream ss;
ss << pair1 << " " << pair2 << " " << pair3;
// strings are already in hex, so we use them as is
ss >> std::hex // change radix to 16
>> i1 >> i2 >> i3;
// now show what happened
std::cout << "Confirm2:" << std::endl;
std::cout << "i1: " << i1 << std::endl;
std::cout << "i2: " << i2 << std::endl;
std::cout << "i3: " << i3 << std::endl << std::endl;
// output now:
// i1: 1
// i2: 140
// i3: 199
// not what you expected? Though correct,
// now we can see we have the wrong radix for output
// add output radix to cout stream
std::cout << std::hex // add radix info here!
<< "i1: " << i1 << std::endl
// Note: only need to do once for std::cout
<< "i2: " << i2 << std::endl
<< "i3: " << i3 << std::endl << std::endl
<< std::dec;
// output now looks correct, and easily comparable to input
// i1: 1
// i2: 8c
// i3: c7
// So: What next?
// read the entire string of hex input into a single string
// separate this into pairs of chars (perhaps using
// string::substr())
// put space separated pairs into stringstream ss
// extract hex values until ss.eof()
// probably should add error checks
// and, of course, figure out how to use a loop for these steps
//
// alternative to consider:
// read 1 char at a time, build a pairing, convert, repeat
}
//
// Eventually, you should get far enough to discover that the
// extracts I have done are integers, but you want to pack them
// into an array of binary bytes.
//
// You can go back, and recode to extract bytes (either
// unsigned char or uint8_t), which you might find interesting.
//
// Or ... because your input is hex, and the largest 2 char
// value will be 0xff, and this fits into a single byte, you
// can simply static_cast them (I use unsigned char)
unsigned char bin[] = {static_cast<unsigned char>(i1),
static_cast<unsigned char>(i2),
static_cast<unsigned char>(i3) };
// Now confirm by casting these back to ints to cout
std::cout << "Confirm4: "
<< std::hex << std::setw(2) << std::setfill('0')
<< static_cast<int>(bin[0]) << " "
<< static_cast<int>(bin[1]) << " "
<< static_cast<int>(bin[2]) << std::endl;
// you also might consider a vector (and i prefer uint8_t)
// because push_back operations does a lot of hidden work for you
std::vector<uint8_t> bytes;
bytes.push_back(static_cast<uint8_t>(i1));
bytes.push_back(static_cast<uint8_t>(i2));
bytes.push_back(static_cast<uint8_t>(i3));
// confirm
std::cout << "\nConfirm5: ";
for (size_t i=0; i<bytes.size(); ++i)
std::cout << std::hex << std::setw(2) << std::setfill(' ')
<< static_cast<int>(bytes[i]) << " ";
std::cout << std::endl;
Note: The cout (or ss) of bytes or char can be confusing, not always giving the result you might expect. My background is embedded software, and I have surprisingly small experience making stream i/o of bytes work. Just saying this tends to bias my work when dealing with stream i/o.
// other considerations:
//
// you might read 1 char at a time. this can simplify
// your loop, possibly easier to debug
// ... would you have to detect and remove eoln? i.e. '\n'
// ... how would you handle a bad input
// such as not hex char, odd char count in a line
//
// I would probably prefer to use getline(),
// it will read until eoln(), and discard the '\n'
// then in each string, loop char by char, creating char pairs, etc.
//
// Converting a vector<uint8_t> to char bytes[] can be an easier
// effort in some ways. A vector<> guarantees that all the values
// contained are 'packed' back-to-back, and contiguous in
// memory, just right for binary stream output
//
// vector.size() tells how many chars have been pushed
//
// NOTE: the formatted 'insert' operator ('<<') can not
// transfer binary data to a stream. You must use
// stream::write() for binary output.
//
std::stringstream ssOut;
// possible approach:
// 1 step reinterpret_cast
// - a binary block output requires "const char*"
const char* myBuff = reinterpret_cast<const char*>(&myBytes.front());
ssOut.write(myBuff, myBytes.size());
// block write puts binary info into stream
// confirm
std::cout << "\nConfirm6: ";
std::string s = ssOut.str(); // string with binary data
for (size_t i=0; i<s.size(); ++i)
{
// because binary data is _not_ signed data,
// we need to 'cancel' the sign bit
unsigned char ukar = static_cast<unsigned char>(s[i]);
// because formatted output would interpret some chars
// (like null, or \n), we cast to int
int intVal = static_cast<int>(ukar);
// cast does not generate code
// now the formatted 'insert' operator
// converts and displays what we want
std::cout << std::hex << std::setw(2) << std::setfill('0')
<< intVal << " ";
}
std::cout << std::endl;
//
//
return (0);
} // int t194(void)
The below snippet should be helpful!
std::ifstream input( "filePath", std::ios::binary );
std::vector<char> hex((
std::istreambuf_iterator<char>(input)),
(std::istreambuf_iterator<char>()));
std::vector<char> bytes;
for (unsigned int i = 0; i < hex.size(); i += 2) {
std::string byteString = hex.substr(i, 2);
char byte = (char) strtol(byteString.c_str(), NULL, 16);
bytes.push_back(byte);
}
char* byteArr = bytes.data()
The way I understand your question is that you want just the binary representation of the numbers, i.e. remove the ascii (or ebcdic) part. Your output array will be half the length of the input array.
Here is some crude pseudo code.
For each input char c:
if (isdigit(c)) c -= '0';
else if (isxdigit(c) c -= 'a' + 0xa; //Need to check for isupper or islower)
Then, depending on the index of c in your input array:
if (! index % 2) output[outputindex] = (c << 4) & 0xf0;
else output[outputindex++] = c & 0x0f;
Here is a function that takes a string as in your description, and outputs a string that has \x in front of each digit.
#include <iostream>
#include <algorithm>
#include <string>
std::string convertHex(const std::string& str)
{
std::string retVal;
std::string hexPrefix = "\\x";
if (!str.empty())
{
std::string::const_iterator it = str.begin();
do
{
if (std::distance(it, str.end()) == 1)
{
retVal += hexPrefix + "0";
retVal += *(it);
++it;
}
else
{
retVal += hexPrefix + std::string(it, it+2);
it += 2;
}
} while (it != str.end());
}
return retVal;
}
using namespace std;
int main()
{
cout << convertHex("01000000d08c9ddf0115d1118c7a00c04") << endl;
cout << convertHex("015d");
}
Output:
\x01\x00\x00\x00\xd0\x8c\x9d\xdf\x01\x15\xd1\x11\x8c\x7a\x00\xc0\x04
\x01\x5d
Basically it is nothing more than a do-while loop. A string is built from each pair of characters encountered. If the number of characters left is 1 (meaning that there is only one digit), a "0" is added to the front of the digit.
I think I'd use a proxy class for reading and writing the data. Unfortunately, the code for the manipulators involved is just a little on the verbose side (to put it mildly).
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
struct byte {
unsigned char ch;
friend std::istream &operator>>(std::istream &is, byte &b) {
std::string temp;
if (is >> std::setw(2) >> std::setprecision(2) >> temp)
b.ch = std::stoi(temp, 0, 16);
return is;
}
friend std::ostream &operator<<(std::ostream &os, byte const &b) {
return os << "\\x" << std::setw(2) << std::setfill('0') << std::setprecision(2) << std::hex << (int)b.ch;
}
};
int main() {
std::istringstream input("01000000d08c9ddf115d1118c7a00c04");
std::ostringstream result;
std::istream_iterator<byte> in(input), end;
std::ostream_iterator<byte> out(result);
std::copy(in, end, out);
std::cout << result.str();
}
I do really dislike how verbose iomanipulators are, but other than that it seems pretty clean.
You can try a loop with fscanf
unsigned char b;
fscanf(pFile, "%2x", &b);
Edit:
#define MAX_LINE_SIZE 128
FILE* pFile = fopen(...);
char fromFile[MAX_LINE_SIZE] = {0};
char b = 0;
int currentIndex = 0;
while (fscanf (pFile, "%2x", &b) > 0 && i < MAX_LINE_SIZE)
fromFile[currentIndex++] = b;

How to truncate a string [formating] ? c++

I want to truncate a string in a cout,
string word = "Very long word";
int i = 1;
cout << word << " " << i;
I want to have as an output of the string a maximum of 8 letters
so in my case, I want to have
Very lon 1
instead of :
Very long word 1
I don't want to use the wget(8) function, since it will not truncate my word to the size I want unfortunately. I also don't want the 'word' string to change its value ( I just want to show to the user a part of the word, but keep it full in my variable)
I know you already have a solution, but I thought this was worth mentioning: Yes, you can simply use string::substr, but it's a common practice to use an ellipsis to indicate that a string has been truncated.
If that's something you wanted to incorporate, you could just make a simple truncate function.
#include <iostream>
#include <string>
std::string truncate(std::string str, size_t width, bool show_ellipsis=true)
{
if (str.length() > width)
if (show_ellipsis)
return str.substr(0, width) + "...";
else
return str.substr(0, width);
return str;
}
int main()
{
std::string str = "Very long string";
int i = 1;
std::cout << truncate(str, 8) << "\t" << i << std::endl;
std::cout << truncate(str, 8, false) << "\t" << i << std::endl;
return 0;
}
The output would be:
Very lon... 1
Very lon 1
As Chris Olden mentioned above, using string::substr is a way to truncate a string. However, if you need another way to do that you could simply use string::resize and then add the ellipsis if the string has been truncated.
You may wonder what does string::resize? In fact it just resizes the used memory (not the reserved one) by your string and deletes any character beyond the new size, only keeping the first nth character of your string, with n being the new size. Moreover, if the new size is greater, it will expand the used memory of your string, but this aspect of expansion is straightforward I think.
Of course, I don't want to suggest a 'new best way' to do it, it's just another way to truncate a std::string.
If you adapt the Chris Olden truncate function, you get something like this:
#include <iostream>
#include <string>
std::string& truncate(std::string& str, size_t width, bool show_ellipsis=true) {
if (str.length() > width) {
if (show_ellipsis) {
str.resize(width);
return str.append("...");
}
else {
str.resize(width);
return str;
}
}
return str;
}
int main() {
std::string str = "Very long string";
int i = 1;
std::cout << truncate(str, 8) << "\t" << i << std::endl;
std::cout << truncate(str, 8, false) << "\t" << i << std::endl;
return 0;
}
Even though this method does basically the same, note that this method takes and returns a reference to the modified string, so be careful with it since this string could be destroyed because of an external event in your code. Thus if you don't want to take that risk, just remove the references and the function becomes:
std::string truncate(std::string str, size_t width, bool show_ellipsis=true) {
if (str.length() > width) {
if (show_ellipsis) {
str.resize(width);
return str + "...";
}
else {
str.resize(width);
return str;
}
}
return str;
}
I know it's a little bit late to post this answer. However it might come in handy for future visitors.