Print one line to multiple lines with \n or space or fixed length

Hello,

I would like to ask for your help to review my code. As the title, I would like to print one line to multiple lines with special character as `\n` (ASCII 10), space (ASCII 32). The priority is `n`, ` `, if line doesn't contain those those characters, the code will split the string with fixed length (48, 96, ...)


1. Variables is very unclear, but I can't think a new name is better. Can you help me with those?
2. Substring from original string to a new one is copy constructor, Do you have the another approve to print it without substring?

Many thanks,
Seal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
void PrintMultipleLine(const std::string &i_message)
{
	size_t m_messageLength = i_message.length();
	size_t m_indexPrefix = 0;
	size_t m_lastIndexPrefix = 0;
	std::vector<size_t> posSubstr;
	static const size_t MAX_OUTPUT_STRING_LENGHT = 48;
	char m_character_to_cut_string = 10; // New line
	bool m_hasPrefixInString = true;
	m_indexPrefix = i_message.find(m_character_to_cut_string);
	std::string o_message;
	if(m_indexPrefix == std::string::npos) // Have no '\n' in the string
	{
		m_character_to_cut_string = 32; // space
	}
	m_indexPrefix = i_message.find(m_character_to_cut_string);
	if(m_indexPrefix == std::string::npos) // Have no space in the string
	{
		 m_hasPrefixInString = false;
	}
	m_indexPrefix = 0;
	while (m_messageLength > MAX_OUTPUT_STRING_LENGHT)
	{
		if(m_hasPrefixInString)
		{
			m_indexPrefix = i_message.find(m_character_to_cut_string, m_indexPrefix + MAX_OUTPUT_STRING_LENGHT);
			posSubstr.push_back(m_indexPrefix);
			if(m_indexPrefix != std::string::npos)
			{
				// std::string output_string = i_message.substr(m_lastIndexPrefix, m_indexPrefix - m_lastIndexPrefix);
				// std::cout << output_string << std::endl;
				m_messageLength -= (m_indexPrefix - m_lastIndexPrefix);
				m_lastIndexPrefix = m_indexPrefix + 1;
			}
			else
				break;
		}
		else
		{
			// std::string output_string = i_message.substr(m_lastIndexPrefix, MAX_OUTPUT_STRING_LENGHT);
			// std::cout << output_string << std::endl;
			m_lastIndexPrefix += MAX_OUTPUT_STRING_LENGHT;
			m_messageLength -= MAX_OUTPUT_STRING_LENGHT;
			posSubstr.push_back(m_lastIndexPrefix);
		}
	}
	// std::string output_string = i_message.substr(m_lastIndexPrefix, i_message.length() - m_lastIndexPrefix);
	// std::cout << output_string << std::endl;
	for (size_t i = 0; i < posSubstr.size() - 1; i++)
	{
		o_message = i_message.substr(posSubstr[i], posSubstr[i + 1] - posSubstr[i]);
		std::cout << o_message << std::endl;
		o_message.clear();
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>

struct printer
{
    const std::string sep = "\n " ;
    const std::size_t line_sz = 48 ;

    std::string curr_line ;

    printer& operator<< ( char c )
    {
        curr_line += c ; // append the character to the current line

        // if c is a separator or character or line size has been reached
        if( sep.find(c) != std::string::npos || curr_line.size() == line_sz )
        {
            std::cout << curr_line ; // print the current line
            if( curr_line.back() != '\n' ) std::cout << '\n' ; // print a new line if required
            curr_line.clear() ; // start a new line
        }
        return *this ;
    }

    ~printer() // at the end
    {
        if( !curr_line.empty() )
        {
            std::cout << curr_line ; // print the last line
            if( curr_line.back() != '\n' ) std::cout << '\n' ; // print a new line if required
        }
    }
};
Re the OP's original post and method. You might find it easier to work with iterator's and use std::find() rather than string.find(). That way you specify the start of the find and also when to stop. So if you want a line no longer than say 48 then the end iterator is the minimum of string end and string begin + 48. Everything then can be done within a loop. Then you print the required part using std::string_view from required start to required end.

Thanks for your suggestions. The code of @JLBorges is good reference.

In the case, I can't use std::cout because I print the log on Android OS. So I need to split the line to multi-line

int __android_log_write(
int prio,
const char *tag,
const char *text
)

One way would be to create a vector of the multiple required lines. This can then be used/displayed as required. Perhaps something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <string>
#include <string_view>
#include <iostream>
#include <vector>

auto split(std::string_view str) {
	static constexpr size_t maxline {5};

	std::vector<std::string_view> vsv;
	auto curitt {str.begin()}, curend (str.begin());

	do {
		curend = str.end() - curitt > maxline ? curitt + maxline : str.end();

		auto lf {curitt}, spc {curitt};

		for (auto itr {curitt}; itr < curend; ++itr)
			if (*itr == '\n')
				lf = itr;
			else if (*itr == ' ')
				spc = itr;

		if (lf > spc) {
			vsv.emplace_back(curitt, lf);
			curitt = lf + 1;
		} else if (spc > curitt) {
			vsv.emplace_back(curitt, spc);
			curitt = spc + 1;
		} else {
			vsv.emplace_back(curitt, curend);
			curitt = curend;
		}

	} while (curend < str.end());

	return vsv;
}

int main() {
	const std::string tst {"abc\nde fghz\njhqwerty"};
	const auto lines {split(tst)};

	for (const auto& l : lines)
		std::cout << l << '\n';
}



abc
de
fghz
jhqwe
rty

Last edited on
> I can't use std::cout because I print the log on Android OS.

Just replace the std::cout line with an equivalent call to the android log function.
For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <string>

int android_log_write( int prio, const char *tag, const char *text ) ;

struct printer
{
    const std::string sep = "\n " ;
    const std::size_t line_sz = 48 ;
    const int prio = 1 ;
    const std::string tag = "printer" ;

    std::string curr_line ;

    void do_write() // print the current line to android log
    {
        if( !curr_line.empty() )
        {
            // add a new line if the line does not end with '\n'
            if( curr_line.back() != '\n' ) curr_line += '\n' ;
            android_log_write( prio, tag.c_str(), curr_line.c_str() ) ;
        }
    }

    printer& operator<< ( char c )
    {
        curr_line += c ; // append the character to the current line

        // if c is a separator character or line size has been reached
        if( sep.find(c) != std::string::npos || curr_line.size() == line_sz )
        {
            do_write() ; // print the current line
            curr_line.clear() ; // and start a new line
        }
        return *this ;
    }

    ~printer() { do_write() ; } // at the end, print the last line
};
Last edited on
Thank you, guys. Those solutions work expected and perfect.
Topic archived. No new replies allowed.