Java 中的正则表达式映射实现



有没有Map的Java实现,哪些键是正则表达式模式。这种数据结构可能吗? 找到了几个手工制作的解决方案,例如 https://wiki.apache.org/jakarta/RegexpKeyedMap,但我想要一个经过良好测试的库。

作为客户,我想要这个

map.put('^RESOURCE.*', () -> { /* some action*/});
map.put('USER|ACCOUNT', () -> { /* do action*/}};
map.put('PRODUCT', () -> { /* do action */}};

例如

String entityType = 'RESOURCE_TYPE_1';
.....
Supplier<MyBatisMapper> action = mapers.get(entityType)
MyBatisMapper mapper = action.get();
mapper.update(entity);

它将用作静态配置。因此,删除功能不是必需的。

编辑

目前,我们的项目中有几个大型开关,任务是使条件更加复杂。喜欢(在伪代码中):

switch (type) {
case 'USER' || 'ACCOUNT' : doAction();
case startsWith('RESOURCE'): doAnotherAction();
...
/* another 10-15 cases */
}

我怀疑什么是最佳方法。有几个想法,但没有一个看起来不错:

  • 使用 if/else 更改开关
  • 制作一些像 dimo414 提议的正则表达式容器。
  • 创建一些用于配置的类。对于问题来说,这看起来太复杂了。

我在时髦中很容易解决这个问题,使

def configuration = [
[matcher: { it.startsWith('RESOURCE' }, action: { /* */}],
[matcher: { it == 'USER' || it == 'ACCOUNT' }, action: { /* */}]
]
...
def result = configuration.find({ it.matcher(type)}).action();

但是对于Java来说,这样的解决方案会太脏了(由于类型转换)。

Map有一个相当复杂的协定,很难(或不可能)正确遵循你所描述的数据结构。例如,没有有意义的方法来实现.entrySet(),因为有无限的有效键。此外,这个"映射"的行为并不真正符合Map的概念目的,因为查找是昂贵的(可能是O(nk),其中k是模式的复杂性)。

我建议避免实现Map,而是定义一个只支持所需行为的专用类。这可能看起来像这样:

/**
* Associates a series of regular expressions with values, allowing the values
* to be looked up by strings that match a pattern.
*
* Note this is a linear-time operation, and that patterns are checked in
* insertion order.
*/
public class RegexLookup<V> {
// Pattern doesn't override .equals()/.hashCode(), so it can't be the map key
// use a LinkedHashMap to ensure ordered search
private final LinkedHashMap<String, Pattern> patterns = new HashMap<>();
private final HashMap<String, V> values = new HashMap<>();
/** Associates a regular expression with a value */
public void putPattern(String regex, V value) {
putPattern(Pattern.compile(regex), regex);
}
/** Associates a regular expression with a value */
public void putPattern(Pattern pattern, V value) {
patterns.put(pattern.pattern(), pattern);
values.put(pattern.pattern(), value);
}
/**
* Looks for a pattern matching the given string, and returns the associated
* value. If not match is found, returns {@link Optional#absent}.
*/
public Optional<V> find(String string) {
for (Entry<String, Pattern> e : patterns.entrySet()) {
if (e.getValue().matcher(string).matches()) {
return Optional.of(values.get(e.getKey()));
}
}
return Optional.absent();
}
/** Returns a read-only view of the underlying pattern:value mapping. */
public Map<String, V> asPatternMap() {
return Collections.unmodifiableMap(values);
}
}

组合比继承有很多好处。除了不需要实现完整的Map契约之外,我们还可以为我们的方法提供更清晰的名称和更好的签名。.find()清楚地传达了我们正在进行可能昂贵的搜索,不像.get()通常暗示要快。

您的示例最终看起来像这样(您可能需要一个标准功能接口作为V类型,但这取决于您需要什么):

RegexLookup<...> configuration = new RegexLookup();
configuration.putPattern('^RESOURCE.*', () -> { /* some action*/});
configuration.putPattern('USER|ACCOUNT', () -> { /* do action*/}};
configuration.putPattern('PRODUCT', () -> { /* do action */}};

然后,您可以使用以下命令检索操作:

Optional<...> action = configuration.find(someString);

这个实现有一些可能的改进,可能让我们比O(nk) 做得更好,比如构造模式的共轭 (|) 和基本上做一个二分搜索,但做额外的正则表达式搜索的开销可能不值得(复杂性变成了O(log(n) * k^2),我认为),所以我肯定想对比上述实现更复杂的东西进行基准测试。

相关内容

  • 没有找到相关文章

最新更新