Basic C++ Text Justification

♀尐吖头ヾ 提交于 2021-01-27 12:11:20

问题


I'm trying to code a program that takes an input line from a file and makes it exactly 80 characters (assume input line always less than 80), and then prints the line. This is done by adding UP TO two spaces after the following punctuation: .,!;? If a line is less than 41 characters, it is printed without modifcation.

If the line is still not 80 characters, random spaces can be added throughout the line, uniformity does not matter for this.

The input file is: Is Lorem Ipsum just dummy text of the printing and typesetting industry? Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

The output file should look like:

This. Notice how each line is justified the same

Here's my code:

const int maxLine = 80;

ifstream fin("unjustified.txt");
ofstream fout("justified.txt");

void randomSpace(string &input);
void spaceAdder(string &input);

int main() {

    string inputLine;

    while (getline(fin, inputLine)) {

        if (inputLine.size() > 40)
        {
            spaceAdder(inputLine);
        }

        else {
            fout << inputLine << endl;

        }
    }

    system("pause");
    fin.close();
    fout.close();
    return 0;
}

void spaceAdder(string &input) {



    int perPos = input.find('.');
    while (perPos != string::npos && input.size() < maxLine) {
        input.insert(perPos + 1, " ");
        perPos = input.find('.', perPos + 1);
    }


    int commaPos = input.find(',');
    while (commaPos != string::npos && input.size() < maxLine) {
        input.insert(commaPos + 1, " ");
        commaPos = input.find(',', commaPos + 1);
    }


    int questPos = input.find('?');
    while (questPos != string::npos && input.size() < maxLine) {
        input.insert(questPos + 1, " ");
        questPos = input.find('?', questPos + 1);
    }


    int semiPos = input.find(';');
    while (semiPos != string::npos && input.size() < maxLine) {
        input.insert(semiPos + 1, " ");
        semiPos = input.find(';', semiPos + 1);
    }


    int exclamPos = input.find('!');
    while (exclamPos != string::npos && input.size() < maxLine) {
        input.insert(exclamPos + 1, " ");
        exclamPos = input.find('!', exclamPos + 1);
    }


    if (input.size() < maxLine) {
        randomSpace(input);


    }
    else
        fout << input << endl;


}



void randomSpace(string &input) {

    srand(time(0));

    while (input.size() < maxLine) {


        int spacePos = input.find(" ");
        bool i = (rand() % 2 == 1) ? true : false;

        if (i = true && spacePos != string::npos)
        {
            input.insert(spacePos, " ");
            spacePos = input.find(" ", spacePos + 1);

        }

    }

    fout << input << endl;
}

However the output that my code creates is:

This. Notice how lines 2 and 4 are not justified with the rest of the text

I cannot for the life of me figure out what is wrong with my code. Please point me in the right direction! Thanks


回答1:


A simple C++ code can be:

std::ifstream input_file_stream( "file" );

unsigned counter = 0;
while( ++counter <= 80 && std::char_traits< char >::not_eof( input_file_stream.peek() ) ){
    std::cout << char ( input_file_stream.get() );
    if( counter == 80 ){
        std::cout << '\n';
        counter = 0;
    }
}

the output length of each line is 80 characters:


NOTE

Instead of using std::cout you can write it to a output-file
Also here some words are missing like the at the end of line 2 and beginning of line 3.
Therefore another solution can be something like this:

input:

Is Lorem Ipsum just dummy text of the printing and typesetting industry? Lorem
Ipsum has been the industry's standard dummy text ever since the 1500s, when
an unknown printer took a galley of type and scrambled it to make a type specimen
book. It has survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum.

C++ code:

std::ifstream input_file_stream( "file" );

unsigned max_size = 0;
for( std::string line; std::getline( input_file_stream, line );  ){
    // find the longest line
    if ( max_size < line.size() ) max_size = line.size();
}

input_file_stream.clear();
input_file_stream.seekg( 0 , std::ios_base::beg );  // rewind

for( std::string line; std::getline( input_file_stream, line );  ){

    if( line.size() == max_size ){
        std::cout << line << '\n';

    } else if (  line.size() > 70 ) {

        line.insert( line.rfind( ' ' ),std::string(  max_size - line.size() ,' ' ) );
        std::cout << line << '\n';

    } else {
        std::cout << line << '\n';
    }
}

input_file_stream.close();

output:

Is Lorem Ipsum just dummy text of the printing and typesetting industry?    Lorem
Ipsum has been the industry's standard dummy text ever since the 1500s,      when
an unknown printer took a galley of type and scrambled it to make a type specimen
book. It has survived not only five centuries, but also the leap into  electronic
typesetting, remaining essentially unchanged. It was popularised in the     1960s
with the release of Letraset sheets containing Lorem Ipsum passages, and     more
recently with desktop publishing software like Aldus PageMaker          including
versions of Lorem Ipsum.

how it works

It is so easy. First of all you need to find the longest line that here is 81 and then based on this longest line you can justify the other lines by using line.rfind (means find last thing) and line.insert to insert what you want. It is up to you that decide what size should be the length of the each line. Here I used between 81 and 70.

Each line is justified based on this line:

an unknown printer took a galley of type and scrambled it to make a type specimen

But here the output is not beautiful since all space have gathered at the end. For that you can spread all space between other space in the else if section like this:

    } else if (  line.size() > 70 ) {

        unsigned need_space = max_size - line.size();
        unsigned count_space = std::count( line.begin(), line.end(), ' ' );

        std::istringstream iss( line );
        std::string temp_line;

        while( need_space-- && count_space-- ){
            std::string temp;
            iss >> temp;
            temp_line +=  temp + "__";
        }
        iss.get();  // get rid of a single space in the iss stream
        // extracts the rest of the iss stream:
        temp_line.append(  std::istreambuf_iterator<char>( iss ), std::istreambuf_iterator<char>() );
        std::cout  << temp_line << '\n';

    } else {
        std::cout << line << '\n';
    }

the output:

Is__Lorem__Ipsum__just dummy text of the printing and typesetting industry? Lorem
Ipsum__has__been__the__industry's__standard dummy text ever since the 1500s, when
an unknown printer took a galley of type and scrambled it to make a type specimen
book.__It has survived not only five centuries, but also the leap into electronic
typesetting,__remaining__essentially__unchanged.__It was popularised in the 1960s
with__the__release__of__Letraset sheets containing Lorem Ipsum passages, and more
recently__with__desktop__publishing__software__like__Aldus__PageMaker__including
versions of Lorem Ipsum.

As you can see here I used __ instead of 2-spaces to show what happens on the output, so you can change it to 2 spaces. Although the code still has a couple of problems such as the line before last that is not fixed as others, but I do not want to make the code complex and I think it will be enough for most cases.




回答2:


Your spaceAdder function is only checking the length of the string

if (input.size() < maxLine) {
    randomSpace(input);
}
else
    fout << input << endl;

after all the punctuation spaces have been added.




回答3:


Where you have:

while (input.size() < maxLine) {...}

I believe you would like to have:

//changed < to <=
while (input.size() <= maxLine) {...}

The same goes for :

if (input.size() < maxLine) {
    randomSpace(input);
}

Change to:

//changed < to <=
if (input.size() <= maxLine) {
    randomSpace(input);
}



回答4:


Here's my take on this. I assumed your input text was actually broken lines and not one long line which would actually make things much simpler as k-five's answer shows.

My input file: (The first line is to ensure multiple punctuation symbols on a line work properly)

a.b,c.d,e?f;g?h!i.j;k?l,ma.b,c.d,e?f;g?h!i.j;k?l,m
Lorem Ipsum just dummy text of the printing and typesetting industry? Lorem
Ipsum has been the industry's standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a type specimen
book. It has survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum.

My code:

#include <iostream>
#include <fstream>
#include <string>
#include <ctime>

using namespace std;

const int maxLine = 80;

void padAfterPunctuation(string &input)
{
    const std::string punct = ".,?;!";

    for (char p : punct)
// for(size_t i = 0; i < punct,size(); ++i) if you can't use a range based for loop.
// use punct[i] rather than p in find below as well.
    {
        size_t pos = 0;
        while ((pos = input.find(p, pos)) != string::npos && input.size() < maxLine)
        {
            input.insert(++pos, " ");
        }
    }
}

void padRandomAfterSpace(string &input)
{
    size_t pos = 0;
    while (input.size() < maxLine)
    {
        pos = input.find(' ', pos);
        if (pos < input.size() && pos != string::npos)
        {
            if (rand() & 1)
            {
                input.insert(pos, " ");
            }
            pos = input.find_first_not_of(' ', pos);
        }
        else
        {
            pos = 0;
        }
    }
}

int main()
{
    srand(time(0));

    ifstream fin("unjustified.txt");
    ofstream fout("justified.txt");
    string inputLine;

    while (getline(fin, inputLine))
    {
        if (inputLine.size() > 40 && inputLine.size() < maxLine)
        {
            padAfterPunctuation(inputLine);
            if (inputLine.size() < maxLine)
            {
                padRandomAfterSpace(inputLine);
            }
        }
        fout << inputLine << endl;
    }
    return 0;
}

I didn't spend too much time figuring out where your code was going wrong but looking at it I suspect c.z. is correct. Rather than add more code to an overly long and complicated function I chose to simplify which makes it easy to check the line length after every space is added.

I also chose to make your files local variables in main and have one place where data is written. It's best to keep scope as small as possible and for each function to have a single responsibility to avoid possibly writing the data more than once. I don't explicitly close the files since they will close automatically when they go out of scope.

Example Output:

a.  b, c.  d,  e?  f; g? h!  i.  j; k? l, ma. b, c. d, e? f; g? h! i. j; k? l, m
Lorem Ipsum  just dummy  text of  the  printing and typesetting industry?  Lorem
Ipsum has been the industry's standard dummy text ever since the 1500s,  when an
unknown printer took  a galley  of type and scrambled it to make a type specimen
book. It has survived not only five centuries, but also the leap into electronic
typesetting,   remaining essentially unchanged.  It was popularised in the 1960s
with the release  of  Letraset sheets containing Lorem Ipsum passages,  and more
recently   with  desktop  publishing  software like  Aldus  PageMaker  including
versions of Lorem Ipsum.


来源:https://stackoverflow.com/questions/42894749/basic-c-text-justification

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!