Handle quotes better

This allows to arbitrary characters like stars into strings. e.g.

MYKEYWORD
'123*456' 2*'Hello, World! (*)' /

is now a valid record with three strings while it threw an exception
before.

This patch works by transferring the removal of the quotes from the
RawDeck class to the readValueToken<T>() function which now has a
specialization for strings that deals with quotes. One small
complication is that the RawDeck needs to be adapted in order not to
split tokens in the middle of strings.

Finally, the StarToken class does not deal with the conversion from
string to the value type of the item anymore which allows it to become
a normal class instead of a template...
This commit is contained in:
Andreas Lauser 2014-09-18 14:47:05 +02:00 committed by Joakim Hove
parent 879f30e3ff
commit 6eb3421f38
7 changed files with 70 additions and 106 deletions

View File

@ -266,14 +266,14 @@ namespace Opm {
else if (parserState->rawKeyword->getKeywordName() == Opm::RawConsts::paths) {
for (size_t i = 0; i < parserState->rawKeyword->size(); i++) {
RawRecordConstPtr record = parserState->rawKeyword->getRecord(i);
std::string pathName = record->getItem(0);
std::string pathValue = record->getItem(1);
std::string pathName = readValueToken<std::string>(record->getItem(0));
std::string pathValue = readValueToken<std::string>(record->getItem(1));
parserState->pathMap.insert(std::pair<std::string, std::string>(pathName, pathValue));
}
}
else if (parserState->rawKeyword->getKeywordName() == Opm::RawConsts::include) {
RawRecordConstPtr firstRecord = parserState->rawKeyword->getRecord(0);
std::string includeFileAsString = firstRecord->getItem(0);
std::string includeFileAsString = readValueToken<std::string>(firstRecord->getItem(0));
boost::filesystem::path includeFile = getIncludeFilePath(parserState, includeFileAsString);
if (verbose)

View File

@ -113,11 +113,11 @@ namespace Opm {
std::string countString;
std::string valueString;
if (isStarToken(token, countString, valueString)) {
StarToken<ValueType> st(token, countString, valueString);
StarToken st(token, countString, valueString);
ValueType value;
if (st.hasValue()) {
value = st.value();
value = readValueToken<ValueType>(st.valueString());
deckItem->push_backMultiple( value , st.count());
} else {
value = self->getDefault();
@ -141,12 +141,12 @@ namespace Opm {
std::string countString;
std::string valueString;
if (isStarToken(token, countString, valueString)) {
StarToken<ValueType> st(token, countString, valueString);
StarToken st(token, countString, valueString);
if (!st.hasValue())
deckItem->push_backDefault( self->getDefault() );
else
deckItem->push_back(st.value());
deckItem->push_back(readValueToken<ValueType>(st.valueString()));
// replace the first occurence of "N*FOO" by a sequence of N-1 times
// "1*FOO". this is slightly hacky, but it makes it work if the

View File

@ -576,7 +576,7 @@ BOOST_AUTO_TEST_CASE(init_defaultvalue_defaultset) {
ParserStringItem itemString(std::string("ITEM1") , "DEFAULT");
RawRecordPtr rawRecord(new RawRecord(("'1*'/")));
DeckItemConstPtr deckItem = itemString.scan(rawRecord);
BOOST_CHECK_EQUAL("DEFAULT", deckItem->getString(0));
BOOST_CHECK_EQUAL("1*", deckItem->getString(0));
rawRecord.reset(new RawRecord("13*/"));
deckItem = itemString.scan(rawRecord);
@ -595,9 +595,9 @@ BOOST_AUTO_TEST_CASE(init_defaultvalue_defaultset) {
BOOST_AUTO_TEST_CASE(scan_all_valuesCorrect) {
ParserItemSizeEnum sizeType = ALL;
ParserStringItem itemString("ITEMWITHMANY", sizeType);
RawRecordPtr rawRecord(new RawRecord("'WELL1' FISK BANAN 3*X OPPLEGG_FOR_DATAANALYSE /"));
RawRecordPtr rawRecord(new RawRecord("'WELL1' FISK BANAN 3*X OPPLEGG_FOR_DATAANALYSE 'Foo$*!% BAR' /"));
DeckItemConstPtr deckItem = itemString.scan(rawRecord);
BOOST_CHECK_EQUAL(7U, deckItem->size());
BOOST_CHECK_EQUAL(8U, deckItem->size());
BOOST_CHECK_EQUAL("WELL1", deckItem->getString(0));
BOOST_CHECK_EQUAL("FISK", deckItem->getString(1));
@ -606,6 +606,7 @@ BOOST_AUTO_TEST_CASE(scan_all_valuesCorrect) {
BOOST_CHECK_EQUAL("X", deckItem->getString(4));
BOOST_CHECK_EQUAL("X", deckItem->getString(5));
BOOST_CHECK_EQUAL("OPPLEGG_FOR_DATAANALYSE", deckItem->getString(6));
BOOST_CHECK_EQUAL("Foo$*!% BAR", deckItem->getString(7));
}
BOOST_AUTO_TEST_CASE(scan_all_withdefaults) {

View File

@ -103,12 +103,14 @@ namespace Opm {
char currentChar;
char tokenStartCharacter=' ';
std::string currentToken = "";
bool inQuote = false;
for (unsigned i = 0; i < m_sanitizedRecordString.size(); i++) {
currentChar = m_sanitizedRecordString[i];
if (charIsSeparator(currentChar)) {
if (!inQuote && charIsSeparator(currentChar)) {
processSeparatorCharacter(currentToken, currentChar, tokenStartCharacter);
} else if (currentChar == RawConsts::quote) {
processQuoteCharacters(currentToken, currentChar, tokenStartCharacter);
inQuote = !inQuote;
processNonSpecialCharacters(currentToken, currentChar);
} else {
processNonSpecialCharacters(currentToken, currentChar);
}
@ -131,19 +133,6 @@ namespace Opm {
}
}
void RawRecord::processQuoteCharacters(std::string& currentToken, const char& currentChar, char& tokenStartCharacter) {
if (currentChar == tokenStartCharacter) {
if (currentToken.size() > 0) {
m_recordItems.push_back(currentToken);
currentToken.clear();
}
tokenStartCharacter = '\0';
} else {
tokenStartCharacter = currentChar;
currentToken.clear();
}
}
void RawRecord::processNonSpecialCharacters(std::string& currentToken, const char& currentChar) {
currentToken += currentChar;
}

View File

@ -31,17 +31,27 @@ namespace Opm {
std::string& valueString);
template <class T>
T readValueToken(const std::string& valueToken ) {
T readValueToken(const std::string& valueString) {
try {
return boost::lexical_cast<T>(valueToken);
return boost::lexical_cast<T>(valueString);
}
catch (boost::bad_lexical_cast&) {
throw std::invalid_argument("Unable to parse string" + valueToken + " to typeid: " + typeid(T).name());
throw std::invalid_argument("Unable to parse string" + valueString + " to typeid: " + typeid(T).name());
}
}
template <>
inline std::string readValueToken<std::string>(const std::string& valueString) {
if (valueString.size() > 0 && valueString[0] == '\'') {
if (valueString.size() < 2 || valueString[valueString.size() - 1] != '\'')
throw std::invalid_argument("Unable to parse string" + valueString + " as a string token");
return valueString.substr(1, valueString.size() - 2);
}
else
return valueString;
}
template <class T>
class StarToken {
public:
StarToken(const std::string& token)
@ -62,12 +72,6 @@ public:
return m_count;
}
T value() const {
if (!hasValue())
throw std::invalid_argument("The input token did not specify a value ");
return m_value;
}
bool hasValue() const {
return !m_valueString.empty();
}
@ -110,13 +114,9 @@ private:
// TODO: decorate the deck with a warning instead?
throw std::invalid_argument("Specifing zero repetitions is not allowed. Token: \'" + token + "\'.");
}
if (!m_valueString.empty())
m_value = readValueToken<T>( m_valueString );
}
ssize_t m_count;
T m_value;
std::string m_countString;
std::string m_valueString;
};

View File

@ -33,8 +33,8 @@ BOOST_AUTO_TEST_CASE(RawRecordGetRecordsCorrectElementsReturned) {
BOOST_CHECK_EQUAL((unsigned) 4, record->size());
BOOST_CHECK_EQUAL("NODIR ", record->getItem(0));
BOOST_CHECK_EQUAL("REVERS", record->getItem(1));
BOOST_CHECK_EQUAL("'NODIR '", record->getItem(0));
BOOST_CHECK_EQUAL("'REVERS'", record->getItem(1));
BOOST_CHECK_EQUAL("1", record->getItem(2));
BOOST_CHECK_EQUAL("20", record->getItem(3));
}
@ -55,8 +55,8 @@ BOOST_AUTO_TEST_CASE(Rawrecord_OperatorThis_OK) {
Opm::RawRecord record(" 'NODIR ' 'REVERS' 1 20 /");
Opm::RawRecordPtr recordPtr(new Opm::RawRecord(" 'NODIR ' 'REVERS' 1 20 /"));
BOOST_CHECK_EQUAL("NODIR ", record.getItem(0));
BOOST_CHECK_EQUAL("REVERS", record.getItem(1));
BOOST_CHECK_EQUAL("'NODIR '", record.getItem(0));
BOOST_CHECK_EQUAL("'REVERS'", record.getItem(1));
BOOST_CHECK_EQUAL("1", record.getItem(2));
BOOST_CHECK_EQUAL("20", record.getItem(3));

View File

@ -24,99 +24,69 @@
BOOST_AUTO_TEST_CASE(NoStarThrows) {
BOOST_REQUIRE_THROW(Opm::StarToken<int> st("Hei...") , std::invalid_argument);
BOOST_REQUIRE_THROW(Opm::StarToken st("Hei...") , std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(InvalidCountThrow) {
BOOST_REQUIRE_THROW( Opm::StarToken<int> st("X*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken<int> st("1.25*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken<int> st("-3*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken<int> st("0*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken<int> st("*123") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken st("X*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken st("1.25*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken st("-3*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken st("0*") , std::invalid_argument);
BOOST_REQUIRE_THROW( Opm::StarToken st("*123") , std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(CountCorrect) {
Opm::StarToken<int> st1("*");
Opm::StarToken<int> st2("5*");
Opm::StarToken<int> st3("54*");
BOOST_CHECK(st1.count() == 1);
Opm::StarToken st1("*");
Opm::StarToken st2("5*");
Opm::StarToken st3("54*");
BOOST_CHECK(st1.countString() == "");
BOOST_CHECK(st2.countString() == "5");
BOOST_CHECK(st3.countString() == "54");
BOOST_CHECK(st1.valueString() == "");
BOOST_CHECK(st2.valueString() == "");
BOOST_CHECK(st3.valueString() == "");
BOOST_CHECK(!st1.hasValue());
BOOST_CHECK(!st2.hasValue());
BOOST_CHECK(!st3.hasValue());
BOOST_REQUIRE_EQUAL(1U , st1.count());
BOOST_REQUIRE_EQUAL(5U , st2.count());
BOOST_REQUIRE_EQUAL(54U , st3.count());
}
BOOST_AUTO_TEST_CASE(NoValueGetValueThrow) {
Opm::StarToken<int> st1("*");
Opm::StarToken<int> st2("5*");
BOOST_CHECK_THROW( st1.value() , std::invalid_argument );
BOOST_CHECK_THROW( st2.value() , std::invalid_argument );
Opm::StarToken st1("*");
Opm::StarToken st2("5*");
BOOST_CHECK_EQUAL( false , st1.hasValue());
BOOST_CHECK_EQUAL( false , st2.hasValue());
}
BOOST_AUTO_TEST_CASE(IntMalformedValueThrows) {
BOOST_CHECK_THROW( Opm::StarToken<int> st1("1*10X") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<int> st1("1*X") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<int> st1("1*10.25") , std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(StarNoCountThrows) {
BOOST_CHECK_THROW( Opm::StarToken<int> st1("*10") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<double> st1("*1.0") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<std::string> st1("*String") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken st1("*10") , std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(DoubleMalformedValueThrows) {
BOOST_CHECK_THROW( Opm::StarToken<double> st1("1*10X") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<double> st1("1*X") , std::invalid_argument);
BOOST_CHECK_THROW( Opm::StarToken<double> st1("1*10.25F") , std::invalid_argument);
}
BOOST_AUTO_TEST_CASE(CorrectIntValue) {
Opm::StarToken<int> st1("1*10");
Opm::StarToken<int> st2("5*20");
BOOST_AUTO_TEST_CASE(CorrectValueString) {
Opm::StarToken st1("1*10.09");
Opm::StarToken st2("5*20.13");
Opm::StarToken st3("1*'123'");
Opm::StarToken st4("1*123*456");
BOOST_CHECK_EQUAL( true , st1.hasValue());
BOOST_CHECK_EQUAL( true , st2.hasValue());
BOOST_CHECK_EQUAL( true , st3.hasValue());
BOOST_CHECK_EQUAL( true , st4.hasValue());
BOOST_CHECK_EQUAL( 10 , st1.value());
BOOST_CHECK_EQUAL( 20 , st2.value());
BOOST_CHECK_EQUAL( "10.09" , st1.valueString());
BOOST_CHECK_EQUAL( "20.13" , st2.valueString());
BOOST_CHECK_EQUAL( "'123'" , st3.valueString());
BOOST_CHECK_EQUAL( "123*456" , st4.valueString());
}
BOOST_AUTO_TEST_CASE(CorrectDoubleValue) {
Opm::StarToken<double> st1("1*10.09");
Opm::StarToken<double> st2("5*20.13");
BOOST_CHECK_EQUAL( true , st1.hasValue());
BOOST_CHECK_EQUAL( true , st2.hasValue());
BOOST_CHECK_EQUAL( 10.09 , st1.value());
BOOST_CHECK_EQUAL( 20.13 , st2.value());
}
BOOST_AUTO_TEST_CASE(CorrectStringValue) {
Opm::StarToken<std::string> st1("1*10.09");
Opm::StarToken<std::string> st2("5*20.13");
BOOST_CHECK_EQUAL( true , st1.hasValue());
BOOST_CHECK_EQUAL( true , st2.hasValue());
BOOST_CHECK_EQUAL( "10.09" , st1.value());
BOOST_CHECK_EQUAL( "20.13" , st2.value());
}
BOOST_AUTO_TEST_CASE( ContainsStar_WithStar_ReturnsTrue ) {
std::string countString, valueString;
BOOST_CHECK_EQUAL( true , Opm::isStarToken("*", countString, valueString) );
@ -125,6 +95,7 @@ BOOST_AUTO_TEST_CASE( ContainsStar_WithStar_ReturnsTrue ) {
BOOST_CHECK_EQUAL( true , Opm::isStarToken("1*2", countString, valueString) );
BOOST_CHECK_EQUAL( false , Opm::isStarToken("12", countString, valueString) );
BOOST_CHECK_EQUAL( false , Opm::isStarToken("'12*34'", countString, valueString) );
}
BOOST_AUTO_TEST_CASE( readValueToken_basic_validity_tests ) {
@ -132,4 +103,7 @@ BOOST_AUTO_TEST_CASE( readValueToken_basic_validity_tests ) {
BOOST_CHECK_THROW( Opm::readValueToken<double>("truls"), std::invalid_argument );
BOOST_CHECK_EQUAL( "3.3", Opm::readValueToken<std::string>("3.3") );
BOOST_CHECK_EQUAL( "OLGA", Opm::readValueToken<std::string>("OLGA") );
BOOST_CHECK_EQUAL( "OLGA", Opm::readValueToken<std::string>("'OLGA'") );
BOOST_CHECK_EQUAL( "123*456", Opm::readValueToken<std::string>("123*456") );
BOOST_CHECK_EQUAL( "123*456", Opm::readValueToken<std::string>("'123*456'") );
}