Monday 30 August 2021

Chapter 20 // Exercise 11 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 11

Given a list<int> as a (by-reference) parameter, make a vector<double> and copy the elements of the list into it. Verify that the copy was complete and correct. Then print the elements sorted in increasing value.


This one was pretty simple as std::vector has a handy range constructor (since C++98). Basically you give it an iterator to a start and end position in the container and it will copy over those values into the vector. It's a nice one-liner:
vector<double> doubleVector(list.begin(), list.end());

Sunday 29 August 2021

Chapter 20 // Exercise 10 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 10

Define a version of the word-counting program where the user can specify the set of whitespace characters.


I guess for this one he meant that the user can supply several characters at once so "a, 1, -, 9" are "whitespace" characters. For this I created a simple function called isCustomWhitespace(char c, string s). This used std::strings find() function to find c in s. I could then just use this like I did in the previous exercise with isspace() and isalpha().

Saturday 28 August 2021

Chapter 20 // Exercise 9 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 9

Define a program that counts the number of words in a Document. Provide two versions: one that defines word as " a whitespace-separated sequence of characters" and one that defines word as "a sequence of consecutive alphabetic characters." For example, with the former definition, alpha.numeric and as12b are both single words, whereas with the second definition they are both two words.


This table on character handling functions is extremely useful:

I didn't know that isspace() will count control characters like \n as spaces. It made this exercise a lot simpler.

For the first one I iterated through every character and if the current character was a space then I increased the word count; but only if the previous character was not a space.

For the seconds one I increased the word count if the current character was not an alphabetic character; but only if the previous character was an alphabetic character.

Thursday 26 August 2021

Chapter 20 // Exercise 8 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 8

Define a function that counts the number of characters in a Document.


This one was pretty simple. Instead of iterating through every character in the document, I just added up the sizes of the vectors in the list that makes up a document.

Tuesday 17 August 2021

Chapter 20 // Exercise 7 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 7

Find the lexicographical last string in an unsorted vector<string>.


This exercise is a "gotcha". Lexicographical order is basically alphabetical order but to computers, uppercase is alphabetically before lowercase so Zebra would come before zany when it should be after.

Since Bjarne goes on about the std library in this chapter I had a poke round the library to see what functions I could use:
  • string::compare() does not compare lexicographically.
  • strcmp() does not compare lexicographically.
  • std::lexicographical_compare() ironically does not compare lexicographically but there is another version that takes a predicate.
Creating a function to do this though was an exercise in Chapter 18 (exercise 3). I'll need to go back and edit that as I didn't stop to think about uppercase and lowercase characters. Bjarne you devious snake.

So instead I created a simple predicate function that you can pass to lexicographical_compare that returns if tolower(char 1) < tolower(char 2). This solves the problem.


Monday 16 August 2021

Chapter 20 // Exercise 6 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 20 // Exercise 6

Write a find-and-replace operation for Documents based on section 20.6.2


It's been so long since I read this chapter I forgot about the second half and had to re-read it.

Then I did some unreal stuff for a month, forgot again and had to re-read it again...

To say I procrastinated is an understatement. This exercise involves getting the code from section 20.6.2 to run. This means you need to write the match() function on page 740. Once you've done that you're halfway there as you have a way to find a word. 

Match() is trivial. Since we have a string and iterators to the start and end of the document, we just loop through the string checking if the contents of the iterator matches each character, advancing the iterator each time round. If we get to the end of the string without returning false, we've found a match.

So that takes care of "find". To "replace", I got a reference to the vector of characters (the line) from the iterator. Worked out at what index the iterator was at by using this:

Then erased the characters from the vector and inserted the new ones.

So that was my first iteration of FindAndReplace(). It's great for finding and replacing individual words and sentences but not sequences of letters that can't be considered words like the example he gives in the chapter (ones containing special characters like secret\nhomestead). This one is a bit trickier. Let's say I have the lines:
"This is a line ending with a secret"
"homestead is a word."
We can return an iterator to point at the start of secret as finding the string "secret\nhomestead" is easy using match(). However, how would the text editor replace this? Remove secret, replace it with the word and remove homestead. Or remove secret and replace homestead with the word. Or even merging the two lines together with the replacement word? 

I decided to go with the last one and merge the lines together; deleting any lines as necessary.

One thing I haven't allowed is the replacement string to insert new lines. So if you want to replace "banana" with "banana\napple" it won't insert a new line. But cout will make it look like a new line has been inserted. I may do that later. 

Chapter 20 // Exercise 6 - Principles & Practice Using C++

Chapter 20 // Exercise 6 - Principles & Practice Using C++

Chapter 20 // Exercise 6 - Principles & Practice Using C++

EDIT 30/06/2023
Whilst doing Chapter 26 - Exercise 7. It asks to create tests for this code. So I got the code off github and found it no longer compiles. I'm guessing they've updated iterator standards over the past few years and it now requires you to have certain features defined. Either way std::find() would no longer work for the iterator class as defined in the book, so I re-wrote the find_text to not use std::find(). You can find that code here: