gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 02:47:09 24 4
gpt4 key购买 nike

是否有 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建议的。
  • 创建一些用于配置的类。对于这个问题来说,这看起来太复杂了。

我在groovy中很容易解决了这个问题,使得

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

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

最佳答案

Map有一个相当复杂的契约(Contract),很难(或不可能)正确遵循您所描述的数据结构。例如,没有有意义的方法来实现 .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() 不同。

您的示例最终看起来像这样(您可能需要一个标准 functional interface 作为 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)),所以我肯定想对比上述实现更复杂的东西进行基准测试。

关于java - Java 中的正则表达式映射实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44416810/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com