A quaternion contains 4 components; 1 Real Component and 3 Imaginary Components. The imaginary components are represented by the suffix i, j, k.
For example, 1 -2i + 3j - 4k
is a quaternion with 1 being the real component and -2, 3, and -4 being the imaginary components.
In this kata you have to parse a string of a quaternion (ex. "1 + 2i - 3j - 4k")
into a list/array of coefficients (ex. [1 2 -3 -4], with the real component first, then i, j, k). However, the quaternion string can be formatted in many different ways...
standard form: 1+2i-3j-4k
missing terms: 1-3k, 2i-4k
missing coefficients: i+j-k
It may not be in the right order: 2i-1+3k-4j
The coefficients may be integers or decimals: 7-2.4i+3.75j-4.0k
If you have missing terms, output 0
for those terms.
If you have missing coefficients, assume that the missing coefficient is 1.
There are some other things to note while parsing:
* There will always be a + or - between terms.
* You will always be passed valid input with at least 1 term, and without repeated components
* All numbers can be assumed to be valid
* You can change numbers into another form after parsing (ex. 3.0 => 3, 0.4 => .4, 7 => 7.0)
#include <array>
#include <string>
#include <regex>
#include <algorithm>
std::array<float, 4> ParseQuaternion(const std::string& t_quaternion)
{
std::smatch matches;
std::regex realCompPattern("(-?)([0-9.]+)*[^ijk]([+]|-|$)");
std::regex_search(t_quaternion, matches, realCompPattern);
float w = matches.empty() ? 0 : std::stof(matches[0]);
auto g = [&](const std::string& t_letter) -> float {
const std::regex pattern(R"((-?)([ (0-9).]+)?)" + t_letter);
std::string result;
if (std::regex_search(t_quaternion, matches, pattern))
{
if (matches[2].matched && matches[2] != " ")
{
auto matchStr = matches[2].str();
matchStr.erase(std::remove(matchStr.begin(), matchStr.end(), ' '), matchStr.end());
result = matches[1].str() + matchStr;
}
else
{
result = matches[1].str() + "1";
}
}
else
{
result = "0";
}
return std::stof(result);
};
auto i = g("i");
auto j = g("j");
auto k = g("k");
return { w, i, j, k };
}
// TODO: Replace examples and use TDD by writing your own tests
Describe(Quaternions)
{
It(AllTests)
{
Assert::That(ParseQuaternion("1 + 2i + 3j + 4k"), Equals(std::array<float, 4>{1, 2, 3, 4}));
Assert::That(ParseQuaternion("-1 + 3i -3j+7k"), Equals(std::array<float, 4>{-1, 3, -3, 7}));
Assert::That(ParseQuaternion("-1-4i-9j-2k"), Equals(std::array<float, 4>{-1, -4, -9, -2}));
Assert::That(ParseQuaternion("17-16i-15j-14k"), Equals(std::array<float, 4>{17, -16, -15, -14}));
Assert::That(ParseQuaternion("7+2i"), Equals(std::array<float, 4>{7, 2, 0, 0}));
Assert::That(ParseQuaternion("2i-6k"), Equals(std::array<float, 4>{0, 2, 0, -6}));
Assert::That(ParseQuaternion("1-5j+2k"), Equals(std::array<float, 4>{1, 0, -5, 2}));
Assert::That(ParseQuaternion("3+4i-9k"), Equals(std::array<float, 4>{3, 4, 0, -9}));
Assert::That(ParseQuaternion("42i+j-k"), Equals(std::array<float, 4>{0, 42, 1, -1}));
Assert::That(ParseQuaternion("6-2i+j-3k"), Equals(std::array<float, 4>{6, -2, 1, -3}));
Assert::That(ParseQuaternion("1+i+j+k"), Equals(std::array<float, 4>{1, 1, 1, 1}));
Assert::That(ParseQuaternion("-1-i-j-k"), Equals(std::array<float, 4>{-1, -1, -1, -1}));
Assert::That(ParseQuaternion("16k-20j+2i-7"), Equals(std::array<float, 4>{-7, 2, -20, 16}));
Assert::That(ParseQuaternion("i+4k-3j+2"), Equals(std::array<float, 4>{2, 1, -3, 4}));
Assert::That(ParseQuaternion("5k-2i+9+3j"), Equals(std::array<float, 4>{9, -2, 3, 5}));
Assert::That(ParseQuaternion("5k-2j+3"), Equals(std::array<float, 4>{3, 0, -2, 5}));
Assert::That(ParseQuaternion("1.75-1.75i-1.75j-1.75k"), Equals(std::array<float, 4>{1.75, -1.75, -1.75, -1.75}));
Assert::That(ParseQuaternion("2.0j-3k+0.47i-13"), Equals(std::array<float, 4>{-13, 0.47, 2.0, -3}));
Assert::That(ParseQuaternion("5.6-3i"), Equals(std::array<float, 4>{5.6, -3, 0, 0}));
Assert::That(ParseQuaternion("k-7.6i"), Equals(std::array<float, 4>{0, -7.6, 0, 1}));
Assert::That(ParseQuaternion("0"), Equals(std::array<float, 4>{0, 0, 0, 0}));
Assert::That(ParseQuaternion("0j+0k"), Equals(std::array<float, 4>{0, 0, 0, 0}));
Assert::That(ParseQuaternion("-0j"), Equals(std::array<float, 4>{0, 0, 0, 0}));
Assert::That(ParseQuaternion("1-0k"), Equals(std::array<float, 4>{1, 0, 0, 0}));
}
};