mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-09 07:22:11 +00:00
ICU-10923 Adding wildcard resource matching.
This commit is contained in:
parent
8db0321f54
commit
7791a58a83
6 changed files with 256 additions and 47 deletions
|
@ -1234,39 +1234,113 @@ void NewResourceBundleTest::TestFilter() {
|
|||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("alabama", alabama.getType(), URES_TABLE);
|
||||
|
||||
ResourceBundle alaska = alabama.get("alaska", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("alaska", alaska.getType(), URES_TABLE);
|
||||
{
|
||||
ResourceBundle alaska = alabama.get("alaska", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("alaska", alaska.getType(), URES_TABLE);
|
||||
|
||||
ResourceBundle arizona = alaska.get("arizona", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("arizona", arizona.getType(), URES_STRING);
|
||||
{
|
||||
ResourceBundle arizona = alaska.get("arizona", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("arizona", arizona.getType(), URES_STRING);
|
||||
assertEquals("arizona", u"arkansas", arizona.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
assertEquals("arizona", u"arkansas", arizona.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
// Filter: california should not be included
|
||||
ResourceBundle california = alaska.get("california", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
}
|
||||
|
||||
// Filter: california should not be included
|
||||
ResourceBundle california = alaska.get("california", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
|
||||
// Filter: connecticut should not be included
|
||||
ResourceBundle connecticut = alabama.get("connecticut", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
// Filter: connecticut should not be included
|
||||
ResourceBundle connecticut = alabama.get("connecticut", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
}
|
||||
|
||||
ResourceBundle fornia = rb.get("fornia", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("fornia", fornia.getType(), URES_TABLE);
|
||||
|
||||
ResourceBundle hawaii = fornia.get("hawaii", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("hawaii", hawaii.getType(), URES_STRING);
|
||||
{
|
||||
ResourceBundle hawaii = fornia.get("hawaii", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("hawaii", hawaii.getType(), URES_STRING);
|
||||
assertEquals("hawaii", u"idaho", hawaii.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
assertEquals("hawaii", u"idaho", hawaii.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
// Filter: illinois should not be included
|
||||
ResourceBundle illinois = fornia.get("illinois", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
}
|
||||
|
||||
// Filter: illinois should not be included
|
||||
ResourceBundle illinois = fornia.get("illinois", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
ResourceBundle mississippi = rb.get("mississippi", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("mississippi", mississippi.getType(), URES_TABLE);
|
||||
|
||||
{
|
||||
ResourceBundle louisiana = mississippi.get("louisiana", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("louisiana", louisiana.getType(), URES_TABLE);
|
||||
|
||||
{
|
||||
ResourceBundle maine = louisiana.get("maine", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("maine", maine.getType(), URES_STRING);
|
||||
assertEquals("maine", u"maryland", maine.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
ResourceBundle iowa = louisiana.get("iowa", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("iowa", iowa.getType(), URES_STRING);
|
||||
assertEquals("iowa", u"kansas", iowa.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
// Filter: missouri should not be included
|
||||
ResourceBundle missouri = louisiana.get("missouri", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
}
|
||||
|
||||
ResourceBundle michigan = mississippi.get("michigan", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("michigan", michigan.getType(), URES_TABLE);
|
||||
|
||||
{
|
||||
ResourceBundle maine = michigan.get("maine", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("maine", maine.getType(), URES_STRING);
|
||||
assertEquals("maine", u"minnesota", maine.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
// Filter: iowa should not be included
|
||||
ResourceBundle iowa = michigan.get("iowa", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
|
||||
ResourceBundle missouri = michigan.get("missouri", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("missouri", missouri.getType(), URES_STRING);
|
||||
assertEquals("missouri", u"nebraska", missouri.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
}
|
||||
|
||||
ResourceBundle nevada = mississippi.get("nevada", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("nevada", nevada.getType(), URES_TABLE);
|
||||
|
||||
{
|
||||
ResourceBundle maine = nevada.get("maine", status);
|
||||
REQUIRE_SUCCESS(status);
|
||||
assertEquals("maine", maine.getType(), URES_STRING);
|
||||
assertEquals("maine", u"new-hampshire", maine.getString(status));
|
||||
REQUIRE_SUCCESS(status);
|
||||
|
||||
// Filter: iowa should not be included
|
||||
ResourceBundle iowa = nevada.get("iowa", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
|
||||
// Filter: missouri should not be included
|
||||
ResourceBundle missouri = nevada.get("missouri", status);
|
||||
REQUIRE_ERROR(U_MISSING_RESOURCE_ERROR, status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//eof
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
-/alabama
|
||||
+/alabama/alaska/arizona
|
||||
-/fornia/illinois
|
||||
-/mississippi
|
||||
+/mississippi/michigan
|
||||
+/mississippi/*/maine
|
||||
-/mississippi/*/iowa
|
||||
+/mississippi/louisiana/iowa
|
||||
|
|
17
icu4c/source/test/testdata/filtertest.txt
vendored
17
icu4c/source/test/testdata/filtertest.txt
vendored
|
@ -17,4 +17,21 @@ filtertest {
|
|||
hawaii {"idaho"}
|
||||
illinois {"indiana"}
|
||||
}
|
||||
mississippi {
|
||||
louisiana {
|
||||
maine {"maryland"}
|
||||
iowa {"kansas"}
|
||||
missouri {"montana"}
|
||||
}
|
||||
michigan {
|
||||
maine {"minnesota"}
|
||||
iowa {"kentucky"}
|
||||
missouri {"nebraska"}
|
||||
}
|
||||
nevada {
|
||||
maine {"new-hampshire"}
|
||||
iowa {"new-mexico"}
|
||||
missouri {"new-york"}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,17 +85,10 @@ void SimpleRuleBasedPathFilter::addRule(const ResKeyPath& path, bool inclusionRu
|
|||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
Tree* node = &fRoot;
|
||||
for (auto& key : path.pieces()) {
|
||||
// note: operator[] auto-constructs default values
|
||||
node = &node->fChildren[key];
|
||||
}
|
||||
if (isVerbose() && (node->fIncluded != PARTIAL || !node->fChildren.empty())) {
|
||||
std::cout << "genrb info: rule on path " << path
|
||||
<< " overrides previous rules" << std::endl;
|
||||
}
|
||||
node->fIncluded = inclusionRule ? INCLUDE : EXCLUDE;
|
||||
node->fChildren.clear();
|
||||
fRoot.applyRule(path, path.pieces().begin(), inclusionRule, status);
|
||||
|
||||
// DEBUG TIP: Enable the following line to view the inclusion tree:
|
||||
//print(std::cout);
|
||||
}
|
||||
|
||||
PathFilter::EInclusion SimpleRuleBasedPathFilter::match(const ResKeyPath& path) const {
|
||||
|
@ -116,10 +109,16 @@ PathFilter::EInclusion SimpleRuleBasedPathFilter::match(const ResKeyPath& path)
|
|||
auto child = node->fChildren.find(key);
|
||||
// Leaf case 1: input path descends outside the filter tree
|
||||
if (child == node->fChildren.end()) {
|
||||
isLeaf = true;
|
||||
break;
|
||||
if (node->fWildcard) {
|
||||
// A wildcard pattern is present; continue checking
|
||||
node = node->fWildcard.get();
|
||||
} else {
|
||||
isLeaf = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
node = &child->second;
|
||||
}
|
||||
node = &child->second;
|
||||
if (node->fIncluded != PARTIAL) {
|
||||
defaultResult = node->fIncluded;
|
||||
}
|
||||
|
@ -143,6 +142,65 @@ PathFilter::EInclusion SimpleRuleBasedPathFilter::match(const ResKeyPath& path)
|
|||
return node->fIncluded;
|
||||
}
|
||||
|
||||
|
||||
SimpleRuleBasedPathFilter::Tree::Tree(const Tree& other)
|
||||
: fIncluded(other.fIncluded), fChildren(other.fChildren) {
|
||||
// Note: can't use the default copy assignment because of the std::unique_ptr
|
||||
if (other.fWildcard) {
|
||||
fWildcard.reset(new Tree(*other.fWildcard));
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleRuleBasedPathFilter::Tree::applyRule(
|
||||
const ResKeyPath& path,
|
||||
std::list<std::string>::const_iterator it,
|
||||
bool inclusionRule,
|
||||
UErrorCode& status) {
|
||||
|
||||
// Base Case
|
||||
if (it == path.pieces().end()) {
|
||||
if (isVerbose() && (fIncluded != PARTIAL || !fChildren.empty())) {
|
||||
std::cout << "genrb info: rule on path " << path
|
||||
<< " overrides previous rules" << std::endl;
|
||||
}
|
||||
fIncluded = inclusionRule ? INCLUDE : EXCLUDE;
|
||||
fChildren.clear();
|
||||
fWildcard.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
// Recursive Step
|
||||
auto& key = *it;
|
||||
if (key == "*") {
|
||||
// Case 1: Wildcard
|
||||
if (!fWildcard) {
|
||||
fWildcard.reset(new Tree());
|
||||
}
|
||||
// Apply the rule to fWildcard and also to all existing children.
|
||||
it++;
|
||||
fWildcard->applyRule(path, it, inclusionRule, status);
|
||||
for (auto& child : fChildren) {
|
||||
child.second.applyRule(path, it, inclusionRule, status);
|
||||
}
|
||||
it--;
|
||||
|
||||
} else {
|
||||
// Case 2: Normal Key
|
||||
auto search = fChildren.find(key);
|
||||
if (search == fChildren.end()) {
|
||||
if (fWildcard) {
|
||||
// Deep-copy the existing wildcard tree into the new key
|
||||
search = fChildren.emplace(key, Tree(*fWildcard)).first;
|
||||
} else {
|
||||
search = fChildren.emplace(key, Tree()).first;
|
||||
}
|
||||
}
|
||||
it++;
|
||||
search->second.applyRule(path, it, inclusionRule, status);
|
||||
it--;
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleRuleBasedPathFilter::Tree::print(std::ostream& out, int32_t indent) const {
|
||||
for (int32_t i=0; i<indent; i++) out << "\t";
|
||||
out << "included: " << kEInclusionNames[fIncluded] << std::endl;
|
||||
|
@ -153,6 +211,13 @@ void SimpleRuleBasedPathFilter::Tree::print(std::ostream& out, int32_t indent) c
|
|||
for (int32_t i=0; i<indent; i++) out << "\t";
|
||||
out << "}" << std::endl;
|
||||
}
|
||||
if (fWildcard) {
|
||||
for (int32_t i=0; i<indent; i++) out << "\t";
|
||||
out << "* {" << std::endl;
|
||||
fWildcard->print(out, indent + 1);
|
||||
for (int32_t i=0; i<indent; i++) out << "\t";
|
||||
out << "}" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleRuleBasedPathFilter::print(std::ostream& out) const {
|
||||
|
|
|
@ -5,9 +5,10 @@
|
|||
#define __FILTERRB_H__
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
|
@ -64,12 +65,20 @@ public:
|
|||
/**
|
||||
* Implementation of PathFilter for a list of inclusion/exclusion rules.
|
||||
*
|
||||
* The wildcard pattern "*" means that the subsequent filters are applied to
|
||||
* every other tree sharing the same parent.
|
||||
*
|
||||
* For example, given this list of filter rules:
|
||||
*
|
||||
* -/alabama
|
||||
* +/alabama/alaska/arizona
|
||||
* -/fornia/hawaii
|
||||
*
|
||||
*/
|
||||
// -/alabama
|
||||
// +/alabama/alaska/arizona
|
||||
// -/fornia/hawaii
|
||||
// -/mississippi
|
||||
// +/mississippi/michigan
|
||||
// +/mississippi/*/maine
|
||||
// -/mississippi/*/iowa
|
||||
// +/mississippi/louisiana/iowa
|
||||
/*
|
||||
* You get the following structure:
|
||||
*
|
||||
* SimpleRuleBasedPathFilter {
|
||||
|
@ -89,6 +98,36 @@ public:
|
|||
* included: EXCLUDE
|
||||
* }
|
||||
* }
|
||||
* mississippi: {
|
||||
* included: EXCLUDE
|
||||
* louisiana: {
|
||||
* included: PARTIAL
|
||||
* iowa: {
|
||||
* included: INCLUDE
|
||||
* }
|
||||
* maine: {
|
||||
* included: INCLUDE
|
||||
* }
|
||||
* }
|
||||
* michigan: {
|
||||
* included: INCLUDE
|
||||
* iowa: {
|
||||
* included: EXCLUDE
|
||||
* }
|
||||
* maine: {
|
||||
* included: INCLUDE
|
||||
* }
|
||||
* }
|
||||
* * {
|
||||
* included: PARTIAL
|
||||
* iowa: {
|
||||
* included: EXCLUDE
|
||||
* }
|
||||
* maine: {
|
||||
* included: INCLUDE
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
class SimpleRuleBasedPathFilter : public PathFilter {
|
||||
|
@ -102,6 +141,12 @@ public:
|
|||
|
||||
private:
|
||||
struct Tree {
|
||||
|
||||
Tree() = default;
|
||||
|
||||
/** Copy constructor */
|
||||
Tree(const Tree& other);
|
||||
|
||||
/**
|
||||
* Information on the USER-SPECIFIED inclusion/exclusion.
|
||||
*
|
||||
|
@ -111,6 +156,13 @@ private:
|
|||
*/
|
||||
EInclusion fIncluded = PARTIAL;
|
||||
std::map<std::string, Tree> fChildren;
|
||||
std::unique_ptr<Tree> fWildcard;
|
||||
|
||||
void applyRule(
|
||||
const ResKeyPath& path,
|
||||
std::list<std::string>::const_iterator it,
|
||||
bool inclusionRule,
|
||||
UErrorCode& status);
|
||||
|
||||
void print(std::ostream& out, int32_t indent) const;
|
||||
};
|
||||
|
|
|
@ -585,9 +585,7 @@ processFile(const char *filename, const char *cp,
|
|||
CharString inputDirBuf;
|
||||
|
||||
char outputFileName[256];
|
||||
|
||||
int32_t dirlen = 0;
|
||||
int32_t filelen = 0;
|
||||
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
|
@ -595,8 +593,6 @@ processFile(const char *filename, const char *cp,
|
|||
if(filename==NULL){
|
||||
status=U_ILLEGAL_ARGUMENT_ERROR;
|
||||
return;
|
||||
}else{
|
||||
filelen = (int32_t)uprv_strlen(filename);
|
||||
}
|
||||
|
||||
if(inputDir == NULL) {
|
||||
|
|
Loading…
Add table
Reference in a new issue