mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Enhancement - Caseless string compare, find
- Merged compare and find functions in from metatask. - Merged unit tests in from metatask.
This commit is contained in:
parent
56edf73d93
commit
3e5ea8cb6c
3 changed files with 111 additions and 2 deletions
|
@ -34,7 +34,7 @@ Context context;
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int main (int argc, char** argv)
|
int main (int argc, char** argv)
|
||||||
{
|
{
|
||||||
UnitTest t (147);
|
UnitTest t (176);
|
||||||
|
|
||||||
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
// void wrapText (std::vector <std::string>& lines, const std::string& text, const int width)
|
||||||
std::string text = "This is a test of the line wrapping code.";
|
std::string text = "This is a test of the line wrapping code.";
|
||||||
|
@ -305,8 +305,58 @@ int main (int argc, char** argv)
|
||||||
t.ok (isWordEnd (text, 11), "isWordEnd (\"Hello, world.\", 11) -> true");
|
t.ok (isWordEnd (text, 11), "isWordEnd (\"Hello, world.\", 11) -> true");
|
||||||
t.notok (isWordEnd (text, 12), "isWordEnd (\"Hello, world.\", 12) -> false");
|
t.notok (isWordEnd (text, 12), "isWordEnd (\"Hello, world.\", 12) -> false");
|
||||||
|
|
||||||
|
// bool compare (const std::string&, const std::string&, bool caseless = false);
|
||||||
|
// Make sure degenerate cases are handled.
|
||||||
|
t.ok (compare ("", ""), "'' == ''");
|
||||||
|
t.notok (compare ("foo", ""), "foo != ''");
|
||||||
|
t.notok (compare ("", "foo"), "'' != foo");
|
||||||
|
|
||||||
|
// Make sure the default is case-sensitive.
|
||||||
|
t.ok (compare ("foo", "foo"), "foo == foo");
|
||||||
|
t.notok (compare ("foo", "FOO"), "foo != foo");
|
||||||
|
|
||||||
|
// Test case-sensitive.
|
||||||
|
t.notok (compare ("foo", "xx", false), "foo != xx");
|
||||||
|
|
||||||
|
t.ok (compare ("foo", "foo", false), "foo == foo");
|
||||||
|
t.notok (compare ("foo", "FOO", false), "foo != FOO");
|
||||||
|
t.notok (compare ("FOO", "foo", false), "FOO != foo");
|
||||||
|
t.ok (compare ("FOO", "FOO", false), "FOO == FOO");
|
||||||
|
|
||||||
|
// Test case-insensitive.
|
||||||
|
t.notok (compare ("foo", "xx", true), "foo != foo (caseless)");
|
||||||
|
|
||||||
|
t.ok (compare ("foo", "foo", true), "foo == foo (caseless)");
|
||||||
|
t.ok (compare ("foo", "FOO", true), "foo == FOO (caseless)");
|
||||||
|
t.ok (compare ("FOO", "foo", true), "FOO == foo (caseless)");
|
||||||
|
t.ok (compare ("FOO", "FOO", true), "FOO == FOO (caseless)");
|
||||||
|
|
||||||
|
// std::string::size_type find (const std::string&, const std::string&, bool caseless = false);
|
||||||
|
// Make sure degenerate cases are handled.
|
||||||
|
t.is ((int) find ("foo", ""), (int) 0, "foo !contains ''");
|
||||||
|
t.is ((int) find ("", "foo"), (int) std::string::npos, "'' !contains foo");
|
||||||
|
|
||||||
|
// Make sure the default is case-sensitive.
|
||||||
|
t.is ((int) find ("foo", "fo"), 0, "foo contains fo");
|
||||||
|
t.is ((int) find ("foo", "FO"), (int) std::string::npos, "foo !contains fo");
|
||||||
|
|
||||||
|
// Test case-sensitive.
|
||||||
|
t.is ((int) find ("foo", "xx", false), (int) std::string::npos, "foo !contains xx");
|
||||||
|
|
||||||
|
t.is ((int) find ("foo", "fo", false), 0, "foo contains fo");
|
||||||
|
t.is ((int) find ("foo", "FO", false), (int) std::string::npos, "foo !contains fo");
|
||||||
|
t.is ((int) find ("FOO", "fo", false), (int) std::string::npos, "foo !contains fo");
|
||||||
|
t.is ((int) find ("FOO", "FO", false), 0, "foo contains fo");
|
||||||
|
|
||||||
|
// Test case-insensitive.
|
||||||
|
t.is ((int) find ("foo", "xx", true), (int) std::string::npos, "foo !contains xx (caseless)");
|
||||||
|
|
||||||
|
t.is ((int) find ("foo", "fo", true), 0, "foo contains fo (caseless)");
|
||||||
|
t.is ((int) find ("foo", "FO", true), 0, "foo contains FO (caseless)");
|
||||||
|
t.is ((int) find ("FOO", "fo", true), 0, "FOO contains fo (caseless)");
|
||||||
|
t.is ((int) find ("FOO", "FO", true), 0, "FOO contains FO (caseless)");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
57
src/text.cpp
57
src/text.cpp
|
@ -27,6 +27,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <strings.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "Context.h"
|
#include "Context.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -462,3 +463,59 @@ bool isWordEnd (const std::string& input, std::string::size_type pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool compare (
|
||||||
|
const std::string& left,
|
||||||
|
const std::string& right,
|
||||||
|
bool caseless /*= false*/)
|
||||||
|
{
|
||||||
|
// Use strcasecmp if required.
|
||||||
|
if (caseless)
|
||||||
|
return strcasecmp (left.c_str (), right.c_str ()) == 0 ? true : false;
|
||||||
|
|
||||||
|
// Otherwise, just use std::string::operator==.
|
||||||
|
return left == right;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
std::string::size_type find (
|
||||||
|
const std::string& text,
|
||||||
|
const std::string& pattern,
|
||||||
|
bool caseless /*= false*/)
|
||||||
|
{
|
||||||
|
// Implement a caseless find, which is really just a loop withing a loop,
|
||||||
|
// comparing lower-case versions of each character in turn.
|
||||||
|
if (caseless)
|
||||||
|
{
|
||||||
|
// Handle empty pattern.
|
||||||
|
const char* p = pattern.c_str ();
|
||||||
|
size_t len = pattern.length ();
|
||||||
|
if (len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Evaluate these once, for performance reasons.
|
||||||
|
const char* t = text.c_str ();
|
||||||
|
const char* start = t;
|
||||||
|
const char* end = start + text.size ();
|
||||||
|
|
||||||
|
for (; t < end - len; ++t)
|
||||||
|
{
|
||||||
|
int diff;
|
||||||
|
for (size_t i = 0; i < len; ++i)
|
||||||
|
if ((diff = tolower (t[i]) - tolower (p[i])))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// diff == 0 means there was no break from the loop, which only occurs
|
||||||
|
// when a difference is detected. Therefore, the loop terminated, and
|
||||||
|
// diff is zero.
|
||||||
|
if (diff == 0)
|
||||||
|
return t - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, just use std::string::find.
|
||||||
|
return text.find (pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -54,6 +54,8 @@ bool noSpaces (const std::string&);
|
||||||
bool noVerticalSpace (const std::string&);
|
bool noVerticalSpace (const std::string&);
|
||||||
bool isWordStart (const std::string&, std::string::size_type);
|
bool isWordStart (const std::string&, std::string::size_type);
|
||||||
bool isWordEnd (const std::string&, std::string::size_type);
|
bool isWordEnd (const std::string&, std::string::size_type);
|
||||||
|
bool compare (const std::string&, const std::string&, bool caseless = false);
|
||||||
|
std::string::size_type find (const std::string&, const std::string&, bool caseless = false);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue