diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cc738d..32b3c7b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,15 +2,14 @@ project(chapterFirstExample) cmake_minimum_required(VERSION 2.6) include_directories($ENV{GMOCK_HOME}/include $ENV{GMOCK_HOME}/gtest/include) -link_directories($ENV{GMOCK_HOME}/mybuild $ENV{GMOCK_HOME}/gtest/mybuild) -add_definitions(-std=c++0x) +link_directories($ENV{GMOCK_HOME}/lib/.libs $ENV{GMOCK_HOME}/gtest/lib/.libs) +add_definitions(-std=c++11) set(CMAKE_CXX_FLAGS "${CMAXE_CXX_FLAGS} -Wall") -set(sources - main.cpp +set(sources + main.cpp SoundexTest.cpp) -add_executable(test ${sources}) -target_link_libraries(test pthread) -target_link_libraries(test gmock) -target_link_libraries(test gtest) - +add_executable(unittests ${sources}) +target_link_libraries(unittests pthread) +target_link_libraries(unittests gmock) +target_link_libraries(unittests gtest) diff --git a/ExpectToFailCompile b/ExpectToFailCompile deleted file mode 100644 index 80d4c17..0000000 --- a/ExpectToFailCompile +++ /dev/null @@ -1 +0,0 @@ -this branch is expected to fail compilation diff --git a/Soundex.h b/Soundex.h new file mode 100644 index 0000000..599bf5c --- /dev/null +++ b/Soundex.h @@ -0,0 +1,93 @@ +#ifndef Soundex_h +#define Soundex_h +#include +#include + +class Soundex { +public: + static const size_t MaxCodeLength{4}; + + std::string encode(const std::string& word) const { + return zeroPad(upperFront(head(word)) + tail(encodedDigits(word))); + } + + std::string encodedDigit(char letter) const { + const std::unordered_map encodings { + {'b', "1"}, {'f', "1"}, {'p', "1"}, {'v', "1"}, + {'c', "2"}, {'g', "2"}, {'j', "2"}, {'k', "2"}, {'q', "2"}, + {'s', "2"}, {'x', "2"}, {'z', "2"}, + {'d', "3"}, {'t', "3"}, + {'l', "4"}, + {'m', "5"}, {'n', "5"}, + {'r', "6"} + }; + auto it = encodings.find(lower(letter)); + return it == encodings.end() ? NotADigit : it->second; + } + +private: + char lower(char c) const { + return std::tolower(static_cast(c)); + } + + std::string head(const std::string& word) const { + return word.substr(0, 1); + } + + std::string tail(const std::string& word) const { + return word.substr(1); + } + + const std::string NotADigit{"*"}; + + std::string encodedDigits(const std::string& word) const { + std::string encoding; + encodeHead(encoding, word); + encodeTail(encoding, word); + return encoding; + } + + void encodeHead(std::string& encoding, const std::string& word) const { + encoding += encodedDigit(word.front()); + } + + void encodeTail(std::string& encoding, const std::string& word) const { + for (auto i = 1u; i < word.length(); i++) { + if (!isComplete(encoding)) + encodeLetter(encoding, word[i], word[i-1]); + } + } + + void encodeLetter(std::string& encoding, char letter, char lastLetter) const { + auto digit = encodedDigit(letter); + if (digit != NotADigit && + (digit != lastDigit(encoding) || isVowel(lastLetter))) + encoding += digit; + } + + bool isVowel(char letter) const { + return + std::string("aeiouy").find(lower(letter)) != std::string::npos; + } + + bool isComplete (const std::string& encoding) const { + return encoding.length() == MaxCodeLength; + } + + std::string zeroPad(const std::string& word) const { + auto zerosNeeded = MaxCodeLength - word.length(); + return word + std::string(zerosNeeded, '0'); + } + + std::string lastDigit(const std::string& encoding) const { + if (encoding.empty()) return NotADigit; + return std::string(1, encoding.back()); + } + + std::string upperFront(const std::string& string) const { + return std::string(1, + std::toupper(static_cast(string.front()))); + } +}; + +#endif diff --git a/SoundexTest.cpp b/SoundexTest.cpp index f44975c..e57bb4b 100644 --- a/SoundexTest.cpp +++ b/SoundexTest.cpp @@ -1,6 +1,61 @@ -#include "gmock/gmock.h" //