Library: utility to interpret a text as bool value (yes/no)

...also fixes the problem with the "expand" mark in DemoGuiRoundtrip
This commit is contained in:
Fischlurch 2018-10-03 04:43:16 +02:00
parent 7655960b23
commit c6b8811af0
7 changed files with 208 additions and 38 deletions

View file

@ -29,7 +29,9 @@
*/
#include "error.hpp"
#include "lib/util.hpp"
#include "lib/format-string.hpp"
#include <boost/algorithm/string.hpp>
#include <functional>
@ -40,12 +42,18 @@ using boost::algorithm::is_any_of;
using boost::algorithm::is_alnum;
using boost::algorithm::is_space;
#include <regex>
using std::regex;
using std::regex_match;
using std::function;
using util::_Fmt;
namespace util {
using std::function;
typedef function<bool(string::value_type)> ChPredicate;
using ChPredicate = function<bool(string::value_type)>;
ChPredicate operator! (ChPredicate p) { return not bind(p,_1); }
// character classes used for sanitising a string
@ -63,12 +71,12 @@ namespace util {
while ( i != e )
{
while ( i != e && !isValid (*i) ) ++i;
while ( i != e && isValid (*i) ) *(j++) = *(i++);
if ( i != e && isPunct (*i) )
while ( i != e && isValid (*i) ) *(j++) = *(i++);
if ( i != e && isPunct (*i) )
{
*j++ = '_';
do ++i;
while ( i != e && isPunct (*i));
while ( i != e && isPunct (*i));
}
}
res.erase(j,res.end());
@ -79,7 +87,7 @@ namespace util {
/**
* @remarks this function just forwards to boost::algorithm::trim_copy.
* Use this call when boost header inclusion is an issue, otherwise
* a direct invocation is likely to perform better, due to inlining.
* a direct invocation is likely to perform better, due to inlining.
*/
string
trim (string const& org)
@ -87,6 +95,29 @@ namespace util {
return boost::algorithm::trim_copy (org);
}
namespace {
regex trueTokens{ "\\s*(true|True|TRUE|yes|Yes|YES|1|\\+)\\s*", regex::ECMAScript | regex::optimize};
regex falseTokens{"\\s*(false|False|FALSE|no|No|NO|0|\\-)\\s*", regex::ECMAScript | regex::optimize};
}
bool
boolVal (string const& textForm)
{
if (regex_match (textForm, trueTokens)) return true;
if (regex_match (textForm, falseTokens)) return false;
throw lumiera::error::Invalid(_Fmt{"String '%s' can not be interpreted as bool value"} % textForm);
}
bool
isYes (string const& textForm) noexcept
{
return regex_match (textForm, trueTokens);
}
} // namespace util

View file

@ -359,8 +359,8 @@ namespace util {
"mixed Ω garbage" --> 'mixed_garbage'
"Bääääh!!" --> 'Bh'
\endverbatim
* @see sanitised-identifier-test.cpp
* @see lib::meta::sanitisedSymbol()
* @see \ref UtilSanitizedIdentifier_test
* @see \ref lib::meta::sanitisedSymbol()
*/
string sanitise (string const& org);
@ -371,6 +371,23 @@ namespace util {
string trim (string const& org);
/** interpret text representation of a boolean value.
* @remarks this function detects the relevant token rather strict....
* - yields `true` for the tokens "true", "True", "TRUE", "yes", "Yes", "YES", "1", "+"
* - yields `false` for the tokens "false", "False", "FALSE", "no", "No, "NO", "0", "-"
* - leading and trailing whitespace is ignored
* @throws lumiera::error::Invalid for any other text content
*/
bool boolVal(string const&);
/** check the given text if it can be interpreted as affirmative answer (bool `true`).
* @remarks this function just fishes for the known `true` tokens and interprets
* all other content as `false`, including empty strings. Never throws.
*/
bool isYes(string const&) noexcept;
/** convenience shortcut: conversion to c-String via string.

View file

@ -44,8 +44,8 @@
#include "lib/idi/entry-id.hpp"
#include "lib/format-string.hpp" //////////////////////////////////////////////////////////////TICKET #1099 : include needed temporarily
//#include "lib/symbol.hpp"
#include "lib/util.hpp"
#include <boost/lexical_cast.hpp>
#include <string>
using lib::hash::LuidH;
@ -58,8 +58,8 @@ using gui::GuiNotification;
using lib::diff::GenNode;
//using util::cStr;
using util::_Fmt; //////////////////////////////////////////////////////////////TICKET #1099 : include needed temporarily
using util::isYes;
using std::string;
using boost::lexical_cast;
namespace proc {
@ -214,7 +214,7 @@ COMMAND_DEFINITION (test_meta_markAction)
{
ID errorLogID = gui::interact::Wizard::getErrorLogID();
GuiNotification::facade().mark (errorLogID
,actionID=="expand"? GenNode{actionID, lexical_cast<bool> (message)} ///////////FIXME : lexical_cast is not suitable. We need a generic bool parse function!
,actionID=="expand"? GenNode{actionID, isYes(message)}
: GenNode{actionID, message});
})
.captureUndo ([](string actionID, string message) -> string

View file

@ -493,22 +493,6 @@ return: 0
END
TEST "create sanitised identifiers" SanitizedIdentifier_test <<END
out-lit: 'Word' --> 'Word'
out-lit: 'a Sentence' --> 'a_Sentence'
out-lit: 'trailing Withespace
out-lit: ' --> 'trailing_Withespace'
out-lit: 'with a lot
out-lit: of Whitespace' --> 'with_a_lot_of_Whitespace'
out-lit: 'with"much (punctuation)[]!' --> 'withmuch_(punctuation)'
out-lit: '§&Ω%€ leading garbage' --> 'leading_garbage'
out-lit: 'mixed Ω garbage' --> 'mixed_garbage'
out-lit: 'Bääääh!!' --> 'Bh'
out-lit: '§&Ω%€' --> ''
return: 0
END
TEST "ScopedHolder_test" ScopedHolder_test <<END
out: checking ScopedHolder<Dummy>...
out: checking ScopedPtrHolder<Dummy>...
@ -588,6 +572,11 @@ return: 0
END
TEST "ownership of malloced data" UniqueMallocOwner_test <<END
return: 0
END
TEST "integer rounding utility" UtilFloordiv_test <<END
return: 0
END
@ -702,12 +691,28 @@ return: 0
END
TEST "ownership of malloced data" UniqueMallocOwner_test <<END
TEST "collection utils" UtilCollection_test <<END
return: 0
END
TEST "collection utils" UtilCollection_test <<END
TEST "util: parse text to bool" UtilParseBool_test <<END
return: 0
END
TEST "util: sanitised identifier" UtilSanitizedIdentifier_test <<END
out-lit: 'Word' --> 'Word'
out-lit: 'a Sentence' --> 'a_Sentence'
out-lit: 'trailing Withespace
out-lit: ' --> 'trailing_Withespace'
out-lit: 'with a lot
out-lit: of Whitespace' --> 'with_a_lot_of_Whitespace'
out-lit: 'with"much (punctuation)[]!' --> 'withmuch_(punctuation)'
out-lit: '§&Ω%€ leading garbage' --> 'leading_garbage'
out-lit: 'mixed Ω garbage' --> 'mixed_garbage'
out-lit: 'Bääääh!!' --> 'Bh'
out-lit: '§&Ω%€' --> ''
return: 0
END

View file

@ -0,0 +1,106 @@
/*
UtilParseBool(Test) - derive bool value from text form
Copyright (C) Lumiera.org
2018, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file util-parse-bool-test.cpp
** unit test \ref UtilParseBool_test
*/
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/util.hpp"
#include <string>
using lumiera::error::LUMIERA_ERROR_INVALID;
namespace util {
namespace test {
class UtilParseBool_test : public Test
{
virtual void
run (Arg)
{
CHECK (boolVal ("true"));
CHECK (boolVal ("True"));
CHECK (boolVal ("TRUE"));
CHECK (boolVal ("yes"));
CHECK (boolVal ("Yes"));
CHECK (boolVal ("YES"));
CHECK (boolVal ("1"));
CHECK (boolVal ("+"));
CHECK (not boolVal ("false"));
CHECK (not boolVal ("False"));
CHECK (not boolVal ("FALSE"));
CHECK (not boolVal ("no"));
CHECK (not boolVal ("No"));
CHECK (not boolVal ("NO"));
CHECK (not boolVal ("0"));
CHECK (not boolVal ("-"));
CHECK (boolVal ("yes "));
CHECK (boolVal (" Yes"));
CHECK (boolVal (" + "));
CHECK (not boolVal (" \n0 "));
VERIFY_ERROR (INVALID, boolVal("") );
VERIFY_ERROR (INVALID, boolVal(" ") );
VERIFY_ERROR (INVALID, boolVal("yEs") );
VERIFY_ERROR (INVALID, boolVal("tRuE") );
VERIFY_ERROR (INVALID, boolVal("falsehood"));
VERIFY_ERROR (INVALID, boolVal("11") );
VERIFY_ERROR (INVALID, boolVal("+1") );
VERIFY_ERROR (INVALID, boolVal("") );
CHECK (isYes ("true"));
CHECK (isYes ("True"));
CHECK (isYes ("TRUE"));
CHECK (isYes ("yes"));
CHECK (isYes ("Yes"));
CHECK (isYes ("1"));
CHECK (isYes ("+"));
CHECK (isYes (" True "));
CHECK (isYes (" \n\n 1 \t "));
CHECK (not isYes (" True and False"));
CHECK (not isYes ("tRuE"));
CHECK (not isYes ("+2"));
CHECK (not isYes ("no"));
CHECK (not isYes ("1010"));
CHECK (not isYes (""));
CHECK (not isYes (" "));
CHECK (not isYes (""));
}
};
LAUNCHER (UtilParseBool_test, "unit common");
}} // namespace util::test

View file

@ -1,5 +1,5 @@
/*
SanitizedIdentifier(Test) - remove non-standard-chars and punctuation
UtilSanitizedIdentifier(Test) - remove non-standard-chars and punctuation
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -20,8 +20,8 @@
* *****************************************************/
/** @file sanitised-identifier-test.cpp
** unit test \ref SanitizedIdentifier_test
/** @file util-sanitised-identifier-test.cpp
** unit test \ref UtilSanitizedIdentifier_test
*/
@ -38,7 +38,7 @@ namespace util {
namespace test {
class SanitizedIdentifier_test : public Test
class UtilSanitizedIdentifier_test : public Test
{
virtual void run (Arg)
{
@ -60,7 +60,7 @@ namespace test {
}
};
LAUNCHER (SanitizedIdentifier_test, "unit common");
LAUNCHER (UtilSanitizedIdentifier_test, "unit common");
}} // namespace util::test

View file

@ -2962,8 +2962,8 @@
<icon BUILTIN="button_ok"/>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538281608933" ID="ID_584897977" MODIFIED="1538281622963" TEXT="mu&#xdf; bool parsen...">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1538281608933" ID="ID_584897977" MODIFIED="1538533889689" TEXT="mu&#xdf; bool parsen...">
<icon BUILTIN="button_ok"/>
<node CREATED="1538281635897" ID="ID_562945035" MODIFIED="1538281651821" TEXT="lexical_cast geht nicht">
<richcontent TYPE="NOTE"><html>
<head>
@ -2978,7 +2978,7 @@
</richcontent>
<icon BUILTIN="button_cancel"/>
<node CREATED="1538281655774" ID="ID_1847834965" MODIFIED="1538281662977" TEXT="kann nur 1 und 0"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1538281664349" ID="ID_1454517361" MODIFIED="1538281687765" TEXT="interessanter Folgefehler">
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1538281664349" FOLDED="true" ID="ID_1454517361" MODIFIED="1538441787807" TEXT="interessanter Folgefehler">
<icon BUILTIN="broken-line"/>
<node CREATED="1538281691097" ID="ID_1911272932" MODIFIED="1538281757024" TEXT="exception killt ProcDispatcher (das ist OK)">
<icon BUILTIN="full-1"/>
@ -3419,7 +3419,9 @@
</richcontent>
</node>
</node>
<node CREATED="1538440332187" HGAP="-48" ID="ID_393079011" MODIFIED="1538440345038" TEXT="Treffer, versenkt" VSHIFT="27">
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1538440332187" HGAP="-48" ID="ID_393079011" MODIFIED="1538440532784" TEXT="Treffer, versenkt" VSHIFT="27">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
<node COLOR="#435e98" CREATED="1538440346730" ID="ID_1456330609" MODIFIED="1538440482615" TEXT="Fehler ist verschwunden">
<richcontent TYPE="NOTE"><html>
<head>
@ -3536,12 +3538,21 @@
</richcontent>
<icon BUILTIN="info"/>
</node>
<node COLOR="#338800" CREATED="1538440505597" ID="ID_1015433202" MODIFIED="1538440524651" TEXT="#1178 Zombie race in GUI Subsystem shutdown">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1538441813086" ID="ID_431066008" MODIFIED="1538533883011" TEXT="neue Hilfsfunktion in util.hpp">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1538533891029" ID="ID_1886289594" MODIFIED="1538533896858" TEXT="Test hierf&#xfc;r">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1537835859576" ID="ID_968868056" MODIFIED="1538263469675" TEXT="CLEAR_ERR">
<icon BUILTIN="button_ok"/>