1   package org.daisy.pipeline.nlp;
2   
3   import java.util.ArrayList;
4   import java.util.Collections;
5   import java.util.Comparator;
6   
7   import org.daisy.pipeline.nlp.impl.MatchRule;
8   
9   public abstract class RuleBasedTextCategorizer extends TextCategorizer {
10  
11  	@Override
12  	public CategorizedWord categorize(String fullcase, String lowercase) {
13  		CategorizedWord res = null;
14  		int k;
15  		// find the first match in the priority-sorted list
16  		for (k = 0; res == null && k < mRules.size(); ++k) {
17  			// k < mRules.size() is not tested because raising an exception
18  			// is the best we can do here
19  			res = mRules.get(k).match(fullcase, lowercase);
20  		}
21  
22  		if (res == null) {
23  			res = new CategorizedWord();
24  			res.category = Category.UNKNOWN;
25  			res.word = fullcase.substring(0, 1);
26  			return res;
27  		}
28  
29  		// select the longest match with the same priority
30  		int priority = mRules.get(k - 1).getPriority();
31  		for (; k < mRules.size() && mRules.get(k).getPriority() == priority; ++k) {
32  			CategorizedWord m = mRules.get(k).match(fullcase, lowercase);
33  			if (m != null && m.word.length() > res.word.length()) {
34  				res = m;
35  			}
36  		}
37  
38  		return res;
39  	}
40  
41  	@Override
42  	public void resetContext() {
43  		// this categorizer does not need any context
44  	}
45  
46  	@Override
47  	public boolean threadsafe() {
48  		return mThreadsafe;
49  	}
50  
51  	// ///// internal helpers //////
52  	protected ArrayList<MatchRule> mRules = new ArrayList<MatchRule>();
53  
54  	protected void addRule(MatchRule rule) {
55  		mRules.add(rule);
56  	}
57  
58  	/**
59  	 * Should only be called once.
60  	 */
61  	@Override
62  	public void compile() {
63  		Collections.sort(mRules, new Comparator<MatchRule>() {
64  			@Override
65  			public int compare(MatchRule r1, MatchRule r2) {
66  				if (r1.getPriority() == r2.getPriority())
67  					return (r1 == r2 ? 0 : -1);
68  				return (r1.getPriority() > r2.getPriority() ? -1 : 1);
69  			}
70  		});
71  		for (MatchRule rule : mRules) {
72  			if (!rule.threadsafe()) {
73  				return;
74  			}
75  		}
76  		mThreadsafe = true;
77  	}
78  
79  	private boolean mThreadsafe = false;
80  }