org.metafacture.commons.tries.WildcardTrie Maven / Gradle / Ivy
Show all versions of metafacture-commons Show documentation
/*
* Copyright 2013, 2014 Deutsche Nationalbibliothek
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.metafacture.commons.tries;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
/**
* A simple Trie, which accepts a trailing wildcard
*
* @param type of value stored
* @author Markus Michael Geipel
* @author Pascal Christoph
*/
public final class WildcardTrie
{
public static final char STAR_WILDCARD = '*';
public static final char Q_WILDCARD = '?';
public static final String OR_STRING = "|";
private static final Pattern OR_PATTERN = Pattern.compile(OR_STRING, Pattern.LITERAL);
private final Node
root = new Node
();
private Set> nodes = new HashSet>();
private Set> nextNodes = new HashSet>();
/**
* Creates an instance of {@link WildcardTrie}.
*/
public WildcardTrie() {
}
/**
* Inserts keys into the trie. Use '|' to concatenate. Use '*' (0,inf) and '?'
* (1,1) to express wildcards.
*
* @param keys pattern of keys to register
* @param value value to associate with the key pattern
*/
public void put(final String keys, final P value) {
if (keys.contains(OR_STRING)) {
final String[] keysSplit = OR_PATTERN.split(keys);
for (final String string : keysSplit) {
simplyPut(string, value);
}
}
else {
simplyPut(keys, value);
}
}
private void simplyPut(final String key, final P value) {
final int length = key.length();
Node node = root;
Node
next = null;
for (int i = 0; i < length; ++i) {
next = node.getNext(key.charAt(i));
if (next == null) {
next = node.addNext(key.charAt(i));
}
node = next;
}
node.addValue(value);
}
/**
* Gets the List of values identified by a key.
*
* @param key the key
* @return the List of
*/
public List
get(final String key) {
nodes.add(root);
final int length = key.length();
for (int i = 0; i < length; ++i) {
for (final Node
node : nodes) {
Node
temp = node.getNext(key.charAt(i));
if (temp != null) {
nextNodes.add(temp);
}
temp = node.getNext(Q_WILDCARD);
if (temp != null) {
nextNodes.add(temp);
}
temp = node.getNext(STAR_WILDCARD);
if (temp != null) {
nextNodes.add(temp);
if (temp != node) {
temp = temp.getNext(key.charAt(i));
if (temp != null) {
nextNodes.add(temp);
}
}
}
}
nodes.clear();
final Set> temp = nodes;
nodes = nextNodes;
nextNodes = temp;
}
return matches();
}
private List matches() {
List
matches = Collections.emptyList();
for (final Node
node : nodes) {
final Set
values = node.getValues();
if (!values.isEmpty()) {
if (matches == Collections.emptyList()) {
matches = new ArrayList
();
}
matches.addAll(values);
}
}
nodes.clear();
nextNodes.clear();
return matches;
}
/**
* Node in the trie.
*
* @param type of the value associated with this node.
*/
private final class Node {
private Set values = Collections.emptySet();
private final CharMap> links = new CharMap>();
protected Node() {
// nothing to do
}
public Node addNext(final char key) {
final Node next = new Node();
links.put(key, next);
if (key == STAR_WILDCARD) {
next.links.put(STAR_WILDCARD, next);
}
return next;
}
public void addValue(final T value) {
if (values == Collections.emptySet()) {
values = new LinkedHashSet();
}
this.values.add(value);
}
public Set getValues() {
return values;
}
public Node getNext(final char key) {
return links.get(key);
}
}
}