Support Regular Expression Suffix for Keyword Matching
This is mostly to have a general solution for matching region level
summary keywords which may reference a user-defined region set (FIP
keyword, e.g., FIPXYZ) through tags like
RPR__XYZ -- Average pressure in region, FIPXYZ region set
ROPR_XYZ -- Oil production rate in region, FIPXYZ region set
RODENXYZ -- Average oil density in region, FIPXYZ region set
The initial approach introduced in commit cfbafc236 was limited to
selected keywords.
To this end, add a new data member
std::string ParserKeyword::m_matchRegexSuffix
and introduce a new member function
bool ParserKeyword::matchesDeckNames()
which matches a candidate keyword string against the m_deckNames,
and, if applicable, as a regular expression against m_deckNames when
appended m_matchRegexSuffix.
This commit is contained in:
@@ -94,7 +94,9 @@ namespace Opm {
|
||||
static bool validInternalName(const std::string& name);
|
||||
static bool validDeckName(const std::string_view& name);
|
||||
bool hasMatchRegex() const;
|
||||
bool hasMatchRegexSuffix() const;
|
||||
void setMatchRegex(const std::string& deckNameRegexp);
|
||||
void setMatchRegexSuffix(const std::string& deckNameRegexp);
|
||||
bool matches(const std::string_view& ) const;
|
||||
bool hasDimension() const;
|
||||
void addRecord( ParserRecord );
|
||||
@@ -154,6 +156,7 @@ namespace Opm {
|
||||
std::unordered_set<std::string> m_validSectionNames;
|
||||
std::string m_matchRegexString;
|
||||
std::regex m_matchRegex;
|
||||
std::string m_matchRegexSuffix{};
|
||||
std::vector< ParserRecord > m_records;
|
||||
std::string m_Description;
|
||||
bool raw_string_keyword = false;
|
||||
@@ -175,6 +178,7 @@ namespace Opm {
|
||||
void initSizeKeyword(bool table_collection, const Json::JsonObject& sizeObject);
|
||||
void addItems( const Json::JsonObject& jsonConfig);
|
||||
void parseRecords( const Json::JsonObject& recordsConfig);
|
||||
bool matchesDeckNames(std::string_view name) const;
|
||||
};
|
||||
|
||||
std::ostream& operator<<( std::ostream&, const ParserKeyword& );
|
||||
|
||||
@@ -318,11 +318,15 @@ std::string KeywordSize::construct() const
|
||||
ParserKeyword(jsonConfig.get_string("name"))
|
||||
{
|
||||
|
||||
if (jsonConfig.has_item("deck_names") || jsonConfig.has_item("deck_name_regex") )
|
||||
if (jsonConfig.has_item("deck_names") ||
|
||||
jsonConfig.has_item("deck_name_regex") ||
|
||||
jsonConfig.has_item("deck_name_regex_suffix"))
|
||||
{
|
||||
// if either the deck names or the regular expression for deck names are
|
||||
// explicitly specified, we do not implicitly add the contents of the 'name'
|
||||
// item to the deck names...
|
||||
clearDeckNames();
|
||||
}
|
||||
|
||||
initSize(jsonConfig);
|
||||
if (jsonConfig.has_item("min_size")) {
|
||||
@@ -503,14 +507,32 @@ std::string KeywordSize::construct() const
|
||||
}
|
||||
|
||||
void ParserKeyword::initMatchRegex(const Json::JsonObject& jsonObject) {
|
||||
if (!jsonObject.has_item("deck_name_regex"))
|
||||
return;
|
||||
if (jsonObject.has_item("deck_name_regex")) {
|
||||
const Json::JsonObject regexStringObject = jsonObject.get_item("deck_name_regex");
|
||||
if (!regexStringObject.is_string())
|
||||
throw std::invalid_argument("The 'deck_name_regex' JSON item of keyword "+m_name+" need to be a string");
|
||||
|
||||
const Json::JsonObject regexStringObject = jsonObject.get_item("deck_name_regex");
|
||||
if (!regexStringObject.is_string())
|
||||
throw std::invalid_argument("The 'deck_name_regex' JSON item of keyword "+m_name+" need to be a string");
|
||||
setMatchRegex(regexStringObject.as_string());
|
||||
}
|
||||
|
||||
setMatchRegex(regexStringObject.as_string());
|
||||
if (jsonObject.has_item("deck_name_regex_suffix")) {
|
||||
if (!jsonObject.has_item("deck_names")) {
|
||||
throw std::invalid_argument {
|
||||
fmt::format("The 'deck_name_regex_suffix' JSON item of "
|
||||
"keyword {} requires an explicit list "
|
||||
"of 'deck_names' too", this->m_name)
|
||||
};
|
||||
}
|
||||
|
||||
const Json::JsonObject regexStringObject = jsonObject.get_item("deck_name_regex_suffix");
|
||||
if (!regexStringObject.is_string())
|
||||
throw std::invalid_argument {
|
||||
fmt::format("The 'deck_name_regex_suffix' JSON item of "
|
||||
"keyword {} must be a string", this->m_name)
|
||||
};
|
||||
|
||||
setMatchRegexSuffix(regexStringObject.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
void ParserKeyword::addItems(const Json::JsonObject& itemsConfig) {
|
||||
@@ -831,40 +853,91 @@ void set_dimensions( ParserItem& item,
|
||||
return !m_matchRegexString.empty();
|
||||
}
|
||||
|
||||
void ParserKeyword::setMatchRegex(const std::string& deckNameRegexp) {
|
||||
bool ParserKeyword::hasMatchRegexSuffix() const {
|
||||
return !this->m_matchRegexSuffix.empty();
|
||||
}
|
||||
|
||||
void ParserKeyword::setMatchRegex(const std::string& deckNameRegexp)
|
||||
{
|
||||
if (deckNameRegexp.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
m_matchRegex = std::regex(deckNameRegexp);
|
||||
m_matchRegexString = deckNameRegexp;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
std::cerr << "Warning: Malformed regular expression for keyword '" << getName() << "':\n"
|
||||
<< "\n"
|
||||
<< e.what() << "\n"
|
||||
<< "\n"
|
||||
<< "Ignoring expression!\n";
|
||||
catch (const std::regex_error&) {
|
||||
throw std::invalid_argument {
|
||||
fmt::format("'{}' is not a valid regular expression ('deck_name_regex') "
|
||||
"for keyword '{}'", deckNameRegexp, this->getName())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void ParserKeyword::setMatchRegexSuffix(const std::string& deckNameRegexp)
|
||||
{
|
||||
if (deckNameRegexp.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const auto sfx = std::regex { deckNameRegexp };
|
||||
this->m_matchRegexSuffix = deckNameRegexp;
|
||||
}
|
||||
catch (const std::regex_error&) {
|
||||
throw std::invalid_argument {
|
||||
fmt::format("'{}' is not a valid regular expression suffix "
|
||||
"('deck_name_regex_suffix') for keyword '{}'",
|
||||
deckNameRegexp, this->getName())
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
bool ParserKeyword::matches(const std::string_view& name ) const {
|
||||
if (!validDeckName(name ))
|
||||
if (!validDeckName(name))
|
||||
return false;
|
||||
|
||||
else if( m_deckNames.count( std::string(name) ) )
|
||||
else if (matchesDeckNames(name))
|
||||
return true;
|
||||
|
||||
else if (hasMatchRegex()) {
|
||||
bool match = std::regex_match( name.begin(), name.end(), m_matchRegex);
|
||||
if (match)
|
||||
return true;
|
||||
else if (hasMatchRegex() && std::regex_match(std::string{name}, m_matchRegex))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParserKeyword::matchesDeckNames(std::string_view name) const
|
||||
{
|
||||
const auto nameStr = std::string { name };
|
||||
|
||||
if (m_deckNames.find(nameStr) != m_deckNames.end()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Last desperate attempt - go through the deckNames list and
|
||||
// interpret the elements as a regular expression.
|
||||
for (const auto& deck_name : this->m_deckNames) {
|
||||
if (std::regex_match(name.begin(), name.end(), std::regex(deck_name)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
// Try to match nameStr against all m_deckNames while treating each
|
||||
// deck name as a regular expression, or, if applicable, when the
|
||||
// name is extended by appending the m_matchRegexSuffix. The latter
|
||||
// is mostly a special case for region-level summary keywords whose
|
||||
// strings may include a tag referring to a user-defined region set
|
||||
// entered using the FIP* keywords--FIPNUM excluded. Examples of
|
||||
// such strings are
|
||||
//
|
||||
// RPR__XYZ
|
||||
// ROPR_XYZ
|
||||
// RODENXYZ
|
||||
//
|
||||
// denoting the region-level average pressures, region-level oil
|
||||
// production rate, and region-level average mass density of oil
|
||||
// respectively defined for the FIPXYZ region set.
|
||||
return std::any_of(this->m_deckNames.begin(),
|
||||
this->m_deckNames.end(),
|
||||
[&nameStr, this](const std::string& deckName)
|
||||
{
|
||||
return std::regex_match(nameStr, std::regex { deckName })
|
||||
|| (this->hasMatchRegexSuffix() &&
|
||||
std::regex_match(nameStr, std::regex { deckName + m_matchRegexSuffix }));
|
||||
});
|
||||
}
|
||||
|
||||
std::string ParserKeyword::createDeclaration(const std::string& indent) const {
|
||||
@@ -970,6 +1043,10 @@ void set_dimensions( ParserItem& item,
|
||||
if (hasMatchRegex())
|
||||
ss << indent << "setMatchRegex(\"" << m_matchRegexString << "\");" << '\n';
|
||||
|
||||
// set the deck name match regex suffix
|
||||
if (hasMatchRegexSuffix())
|
||||
ss << indent << "setMatchRegexSuffix(\"" << m_matchRegexSuffix << "\");\n";
|
||||
|
||||
if (this->keyword_size.code())
|
||||
ss << indent << "setCodeEnd(\"" << this->code_end << "\");" << '\n';
|
||||
|
||||
@@ -1027,6 +1104,7 @@ void set_dimensions( ParserItem& item,
|
||||
if( m_name != rhs.m_name
|
||||
|| this->code_end != rhs.code_end
|
||||
|| m_matchRegexString != rhs.m_matchRegexString
|
||||
|| m_matchRegexSuffix != rhs.m_matchRegexSuffix
|
||||
|| isCodeKeyword() != rhs.isCodeKeyword()
|
||||
|| isDataKeyword() != rhs.isDataKeyword())
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user