Way to move punctuation back to end of word (pig Latin)

Hello,

Pig Latin program here ---
I am really struggling to come up with a way to move punctuation back to where it belongs .... (Ello!hay needs to be be ---> Ellohay!)

I would be so grateful for some pointers. At this point, the program is good to go; all cases are accounted for (y as a consonant/vowel, q-u as a unit vs q, consonants, consonant groups, and vowels) and the capitalization of letters properly transfers. The punctuation dilemma is the downfall.

I am new to this (forum posting and c++) so please do not hesitate to let me know if I need to share more or different information.

Thank you.
> At this point, the program is good to go;
OK, show us.

We can't tell you what need to do to your program to fix this final requirement.
Okay! :D

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

string convert_paragraph(string);
string convert_word(string);
string get_next_word(string, short);
string paragraph_get(string);
void is_upper(string, string&);
bool is_vowel(char);

int main()
{
string line, paragraph;
cout << "\nPlease enter your string to be converted:\n";
paragraph = paragraph_get(line);
pig_paragraph = convert_paragraph(paragraph);
cout << pig_paragraph << endl;

return 0;
}


// allows \n for paragraph option
string paragraph_get(string line)
{
string paragraph;
getline(cin, line);
while (! line.empty())
{
paragraph += line + '\n';
getline(cin, line);
}
return (paragraph);
}


// grabs words out of paragraph
string get_next_word(string paragraph, short i)
{
string word;
char letter;
letter = paragraph[i];
while ( ! isspace(letter) && i < paragraph.length())
{
word = word + letter;
i++;
if (i < paragraph.length())
letter = paragraph[i];
}
return word;
}


// defines vowels
bool is_vowel(char letter)
{
bool vowel;
if (letter == 'a' || letter == 'e' ||
letter == 'i' || letter == 'o' ||
letter == 'u' || letter == 'A' ||
letter == 'E' || letter == 'I' ||
letter == 'O' || letter == 'U')
{
vowel = true;
}
else
{
vowel = false;
}
return vowel;
}

// converts words to pig_words
// leaves numbers alone
string convert_word(string word)
{
bool was_upper;
short i = 0;
string pig_word;
string first = "";
string second = "";
if (is_vowel(word[0]) == true && isalpha(word[0]))
{
pig_word = word + "yay";
}
else if ((is_vowel(word[i]) == false && isalpha(word[0])))
{
while (i < word.length() && word[i] != 'a' && word[i] != 'e' &&
word[i] != 'i' && word[i] != 'o' && word[i] != 'u'
&& word[i] != 'y')
{
first += word[i];
i++;
}
if (i > 0 && word[i] == 'u' && word[i-1] == 'q')
{
first += word[i];
i++;
}
else if (word[i] == 'y' && word[i+1] == 'a' ||
word[i+1] == 'e' || word[i+1] == 'i' || word[i+1] == 'o' ||
word[i+1] == 'u')
{
first += word[i];
i++;
}

while (i < word.length())
{
second += word[i];
i++;
}
pig_word = second + first + "ay";
}
else
{
pig_word = word;
}

return pig_word;
}


// pig latin paragraph
string convert_paragraph (string paragraph)
{
short i = 0, length;
length = paragraph.length();
string word, pig_word, pig_paragraph = "";
while (i < length)
{
word = get_next_word(paragraph, i);
i += word.length() + 1;
is_upper(word, pig_word);
pig_paragraph += pig_word + " ";
}
return pig_paragraph;
}


// swaps capitalization
void is_upper(string word, string& pig_word)
{
bool was_upper;

if (isupper(word[0]))
{
was_upper = true;
word[0] = static_cast<char>(tolower(word[0]));
}

pig_word = convert_word(word);

if (was_upper)
{
pig_word[0] = static_cast<char>(toupper(pig_word[0]));
}

return;
}
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

string convert_paragraph(string);
string convert_word(string);
string get_next_word(string, short);
string paragraph_get(string);
void is_upper(string, string&);
bool is_vowel(char);

int main()
{
string line, paragraph;
cout << "\nPlease enter your string to be converted:\n";
paragraph = paragraph_get(line);
pig_paragraph = convert_paragraph(paragraph);
cout << pig_paragraph << endl;

return 0;
}


// allows \n for paragraph option
string paragraph_get(string line)
{
string paragraph;
getline(cin, line);
while (! line.empty())
{
paragraph += line + '\n';
getline(cin, line);
}
return (paragraph);
}


// grabs words out of paragraph
string get_next_word(string paragraph, short i)
{
string word;
char letter;
letter = paragraph[i];
while ( ! isspace(letter) && i < paragraph.length())
{
word = word + letter;
i++;
if (i < paragraph.length())
letter = paragraph[i];
}
return word;
}


// defines vowels
bool is_vowel(char letter)
{
bool vowel;
if (letter == 'a' || letter == 'e' ||
letter == 'i' || letter == 'o' ||
letter == 'u' || letter == 'A' ||
letter == 'E' || letter == 'I' ||
letter == 'O' || letter == 'U')
{
vowel = true;
}
else
{
vowel = false;
}
return vowel;
}

// converts words to pig_words
// leaves numbers alone
string convert_word(string word)
{
bool was_upper;
short i = 0;
string pig_word;
string first = "";
string second = "";
if (is_vowel(word[0]) == true && isalpha(word[0]))
{
pig_word = word + "yay";
}
else if ((is_vowel(word[i]) == false && isalpha(word[0])))
{
while (i < word.length() && word[i] != 'a' && word[i] != 'e' &&
word[i] != 'i' && word[i] != 'o' && word[i] != 'u'
&& word[i] != 'y')
{
first += word[i];
i++;
}
if (i > 0 && word[i] == 'u' && word[i-1] == 'q')
{
first += word[i];
i++;
}
else if (word[i] == 'y' && word[i+1] == 'a' ||
word[i+1] == 'e' || word[i+1] == 'i' || word[i+1] == 'o' ||
word[i+1] == 'u')
{
first += word[i];
i++;
}

while (i < word.length())
{
second += word[i];
i++;
}
pig_word = second + first + "ay";
}
else
{
pig_word = word;
}

return pig_word;
}


// pig latin paragraph
string convert_paragraph (string paragraph)
{
short i = 0, length;
length = paragraph.length();
string word, pig_word, pig_paragraph = "";
while (i < length)
{
word = get_next_word(paragraph, i);
i += word.length() + 1;
is_upper(word, pig_word);
pig_paragraph += pig_word + " ";
}
return pig_paragraph;
}


// swaps capitalization
void is_upper(string word, string& pig_word)
{
bool was_upper;

if (isupper(word[0]))
{
was_upper = true;
word[0] = static_cast<char>(tolower(word[0]));
}

pig_word = convert_word(word);

if (was_upper)
{
pig_word[0] = static_cast<char>(toupper(pig_word[0]));
}

return;
}
Did you just copy/paste your previous post, or is it as badly indented in your code editor as you've pushed onto us?
https://en.wikipedia.org/wiki/Indentation_style

Next, make sure it compiles.
1
2
3
4
5
6
7
8
9
10
11
 In function 'int main()':
19:1: error: 'pig_paragraph' was not declared in this scope
 In function 'std::string get_next_word(std::string, short int)':
46:32: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
50:7: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
 In function 'std::string convert_word(std::string)':
91:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
103:25: warning: suggest parentheses around '&&' within '||' [-Wparentheses]
111:10: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
80:6: warning: unused variable 'was_upper' [-Wunused-variable]
 

Your line 103 is wrong.

I guess the first thing you can add is
 
bool is_punctuation(char);
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

string convert_paragraph(string);
string convert_word(string);
string get_next_word(string, short);
string paragraph_get(string);
void is_upper(string, string&);
bool is_vowel(char);

int main()
{    
    string line, paragraph, pig_paragraph, word, pig_word;
    cout << "\nPlease enter your string to be converted:\n";
    paragraph = paragraph_get(line);
    pig_paragraph = convert_paragraph(paragraph); 
    cout << pig_paragraph << endl;   
  
   return 0;
 }  
 
 
// allows \n for paragraph option
string paragraph_get(string line)
{
    string paragraph;
    getline(cin, line);
     while (! line.empty())
     {
            paragraph += line + '\n';
            getline(cin, line);
      }
        return (paragraph);
 }

 
 // grabs words out of paragraph
string get_next_word(string paragraph, short i)
{
    string word;
    char letter;
    letter = paragraph[i];
    while ( ! isspace(letter) && i < paragraph.length())
    {
        word = word + letter;
        i++;
        if (i < paragraph.length())
            letter = paragraph[i];
    }
    return word;
}
    
 
// defines vowels
bool is_vowel(char letter)
{
    bool vowel;
    if (letter == 'a' || letter == 'e' ||
        letter == 'i' || letter == 'o' ||
        letter == 'u' || letter == 'A' ||
        letter == 'E' || letter == 'I' ||
        letter == 'O' || letter == 'U')
    {
        vowel = true;
    }
    else 
    {
        vowel = false;
    }
    return vowel;
}

// converts words to pig_words
// leaves numbers alone
string convert_word(string word)
{
    bool was_upper;
    short i = 0;
    string pig_word;
    string first = "";
    string second = "";
    if (is_vowel(word[0]) == true && isalpha(word[0]))
    {
        pig_word = word + "yay";
    }
    else if ((is_vowel(word[i]) == false && isalpha(word[0])))
      {
            while (i < word.length() && word[i] != 'a' && word[i] != 'e' &&
                     word[i] != 'i' && word[i] != 'o' && word[i] != 'u'
                    && word[i] != 'y')
            {
                first += word[i];
                i++;
            }
            if (i > 0 && word[i] == 'u' && word[i-1] == 'q')
            { 
                first += word[i];
                i++;
            }
            else if (word[i] == 'y' && word[i+1] == 'a' || 
                word[i+1] == 'e' || word[i+1] == 'i' || word[i+1] == 'o' ||
                word[i+1] == 'u')
            {
                first += word[i];
                i++;
            }

            while (i < word.length())
            {
                second += word[i];
                i++;
            }                         
        pig_word = second + first + "ay";
    }
    else
    {
        pig_word = word;
    }   
           
    return pig_word;
}
      
    
 // pig latin paragraph
string convert_paragraph (string paragraph)
{
    short i = 0, length;
    length = paragraph.length();
    string word, pig_word, pig_paragraph = "";
    while (i < length)
    {
        word = get_next_word(paragraph, i);
        i += word.length() + 1;
        is_upper(word, pig_word);
        pig_paragraph += pig_word + " ";
    }
    return pig_paragraph;
} 
  

// swaps capitalization
void is_upper(string word, string& pig_word)
{
    bool was_upper;
    
if (isupper(word[0]))
{
    was_upper = true;
    word[0] = static_cast<char>(tolower(word[0]));
}

    pig_word = convert_word(word);
    
    if (was_upper)
    {
       pig_word[0] = static_cast<char>(toupper(pig_word[0]));
    }

    return;
}   
sorry hope that's better
Slightly reformatted:

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

string convert_paragraph(const string&);
string convert_word(const string&);
string get_next_word(const string&, size_t);
string paragraph_get();
void is_upper(string, string&);
bool is_vowel(char);

int main() {
	cout << "\nPlease enter your string to be converted:\n";

	const auto paragraph{ paragraph_get() };

	cout << convert_paragraph(paragraph) << '\n';
}

// allows \n for paragraph option
string paragraph_get() {
	string paragraph;

	for (string line; getline(cin, line) && !line.empty(); paragraph += line + '\n');

	return paragraph;
}

// grabs words out of paragraph
string get_next_word(const string& paragraph, size_t i) {
	string word;
	auto letter{ paragraph[i] };

	while (!isspace(letter) && i < paragraph.length()) {
		word += letter;
		if (++i < paragraph.length())
			letter = paragraph[i];
	}

	return word;
}

// defines vowels
bool is_vowel(char letter) {
	return (letter == 'a' || letter == 'e' ||
		letter == 'i' || letter == 'o' ||
		letter == 'u' || letter == 'A' ||
		letter == 'E' || letter == 'I' ||
		letter == 'O' || letter == 'U');
}

// converts words to pig_words
// leaves numbers alone
string convert_word(const string& word) {
	size_t i {};
	string pig_word;
	string first;
	string second;

	if (is_vowel(word[0]) == true && isalpha(word[0]))
		pig_word = word + "yay";
	else if ((is_vowel(word[i]) == false && isalpha(word[0]))) {
		while (i < word.length() && !is_vowel(word[i]))
			first += word[i++];

		if (i > 0 && word[i] == 'u' && word[i - 1] == 'q')
			first += word[i++];
		else if (word[i] == 'y' && is_vowel(word[i + 1]))
			first += word[i++];

		while (i < word.length())
			second += word[i++];

		pig_word = second + first + "ay";
	} else
		pig_word = word;

	return pig_word;
}

// pig latin paragraph
string convert_paragraph(const string& paragraph)
{
	const size_t length{ paragraph.length() };
	string pig_word, pig_paragraph;

	for (size_t i{ 0 }; i < length; ) {
		const auto word{ get_next_word(paragraph, i) };

		i += word.length() + 1;
		is_upper(word, pig_word);
		pig_paragraph += pig_word + " ";
	}

	return pig_paragraph;
}


// swaps capitalization
void is_upper(string word, string& pig_word) {
	bool was_upper{};

	if (isupper(word[0])) {
		was_upper = true;
		word[0] = static_cast<char>(tolower(static_cast<unsigned char>(word[0])));
	}

	pig_word = convert_word(word);

	if (was_upper)
		pig_word[0] = static_cast<char>(toupper(static_cast<unsigned char>(pig_word[0])));
}


What's the rule to deal with punctuation? How did you accommodate this rule in your original program design?

Last edited on
You are so awesome - thank you for that!!! Seriously appreciate it!!!

The punctuation rule is essentially keeping the punctuation separated from the letters so it too doesn't go through the translation process ---

If the original statement was "Hello, Mary!" the translated statement should be: "Ellohay, Arymay!"

If this program were to run now, as-is, it would spit out "Ello,hay Ary!may".

At this point, I have taken out all attempts to accommodate this rule. My professor had mentioned something about using a process similar to dealing with whitespace--but I can't conjure up any ideas worth mentioning haha
if its not a letter, do something, is what you want.
it looks like nonletters just need to remain in their relative position, so you treat them as whitespace (they create words, eg hello,lolla is 2 words as if the , were a space), solve the word part (hello) and put the 'delimiter' (the comma) back in after that.

this is a tremendous amount of code for the problem at hand... its looking good so far, but wow @ the amount of effort.
Last edited on
You need to preserve characters that are not part of the word. This will automatically fix the issues with punctuation.

So if your input is
Hello    Mary
noting there are several spaces between "Hello" and "Mary", I'd expect the output to be
Ellohay    Arymay
But instead it is
Ellohay Arymay

One way to fix this is to split the input into a sequence of words and non-words, where a word is a sequence of letters, and a non-word is a sequence of punctuation and spaces and whatever else. Collectively words and non-words are called "tokens".

So you look at every token in the input text, sequentially. If a token is a "word", translate it into Pig Latin and print the result. If you get a non-word just print it unchanged.

See this program, a heavily modified version of yours:
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

string convert_word(string);

static bool my_isalpha(unsigned char c) { return std::isalpha(c); } 
static bool my_isupper(unsigned char c) { return std::isupper(c); }
static char my_tolower(unsigned char c) { return std::tolower(c); }
static char my_toupper(unsigned char c) { return std::toupper(c); }

static bool is_vowel(char c) 
{ 
  for (char v: "aeiouAEIOU") 
    if (c == v) return true; 
  return false; 
}

// NOTE(mbozzi): function signature has changed from `string convert_word(string const&)`
// to make it easier to move capital letters around in this function.
// Capital letters need to be moved around so that "Hello" will convert to "Ellohay" 
// and not "elloHay".

string convert_word(string word) {
	size_t i {};
	string pig_word;
	string first;
	string second;
	
	// NOTE(mbozzi): bounds checking added
	if (word.size() == 0) return word;
	
	// NOTE(mbozzi): Make the leading capital letter small, and remember 
	// whether it was done, so this can be undone near the end of the conversion.
	bool const has_leading_majuscule = my_isupper(word[0]);
	if (has_leading_majuscule) word[0] = my_tolower(word[0]);
	
	// TODO(mbozzi): Double check index arithmetic.
	// Maybe word[i+1] or word[i-1] will access out of bounds, 
	// If i is zero or `word.size() - 1`. 
	// I don't see any problems but didn't look very hard.
	if (is_vowel(word[0]) == true && isalpha(word[0]))
		pig_word = word + "yay";
	else if ((is_vowel(word[i]) == false && isalpha(word[0]))) {
		while (i < word.length() && !is_vowel(word[i]))
			first += word[i++];

		if (i > 0 && word[i] == 'u' && word[i - 1] == 'q')
			first += word[i++];
		else if (word[i] == 'y' && is_vowel(word[i + 1]))
			first += word[i++];

		while (i < word.length())
			second += word[i++];

		pig_word = second + first + "ay";
	} else
		pig_word = word;
		
    // NOTE(mbozzi): Make the first letter big again, if needed
	if (has_leading_majuscule) pig_word[0] = my_toupper(pig_word[0]);

	return pig_word;
}

int main()
{
  for (std::string line; std::getline(std::cin, line); ) 
  {
    std::string::size_type begin = 0;
    std::string::size_type end = 0;
    
    for (begin = 0; begin < line.size(); begin = end)
    {
      bool const is_word = my_isalpha(line[begin]);
      
      if (is_word) while (end < line.size() &&  my_isalpha(line[end])) ++end;
      else         while (end < line.size() && !my_isalpha(line[end])) ++end;

      auto const token = line.substr(begin, end - begin); 
      
      std::cout << (is_word? convert_word(token): token); 
    }
    
    std::cout << '\n';
  }
}


Live demo here:
https://godbolt.org/z/9Td34vod1
Last edited on
Oh my gosh, thank you Jonnin and Mbozzi, I appreciate the help so much! I was getting so discouraged and I now feel like I have direction. The program looks great, it was awesome getting to run it and use punctuation...felt so good! hahaha
Just a comment to assist with future programs. Before starting to code, first design the program. What's the input, what's the output, what algorithms are needed, what classes/structs are required, what data structures are needed? How would you perform the task using pen and paper? What detailed instructions would you give to someone else to do this who hasn't seen the requirement to accomplish the task? What functions are required?

Once you know/document this, then you design the program. Then code the program from the design. Compile and test frequently. As a rough rule of thumb, for the overall time to produce a program about 50% for design, 30% - 40% for coding and 10% - 20% for testing and debugging.
Topic archived. No new replies allowed.