Reputation: 15136
I am trying to create a simple regex kind of thing for my own use where a character in a string can either be an exact match or one in among a set of characters belonging to a group (e.g., Group CAPS will have all uppercase characters - 'A', 'B', etc.). Therefore a regex such as - CAPS p p l e
- should match 'Apple' or a regex such as - DIGIT DIGIT . DIGIT
- should match 76.3.
I am trying to store this regex pattern in an array {CAPS, 'p', 'p', 'l', 'e'}
.
Now, Java will allow me to declare an array of type char[]/Character[]
or Group[]
, where Group is a class I have constructed that represents such groups of characters. If I need to have a hybrid array to be able to store above mentioned patterns, what other options do I have other than declaring an array of type Object[]
?
I really don't want to be dealing with an array of type Object[]
.
Upvotes: 2
Views: 713
Reputation: 5661
You can employ the Composite design pattern to model this situation. This pattern is useful where you need to treat an object type as well as the collection of the objects of that type in the same way. You can also use Chain of Responsibility pattern along with it.
Basically you would define classes like this (lets say that you need a matches() method):
class Pattern {
IPatternComponent[] pattern;
boolean matches(String str) {
for(int i = 0; i < str.length; i++) {
if(!pattern[i].matches(str.charAt(i)))
return false;
}
return true;
}
}
interface IPatternComponent {
boolean matches(char ch);
}
class Simple implements IPatternComponent {
char ch;
boolean matches(char ch) {
return (this.ch == ch);
}
}
class Group implements IPatternComponent {
Set<IPatternComponent> components;
boolean matches(char charToMatch) {
for(IPatternComponent comp : components) {
if(comp.matches(charToMatch)
return true;
}
return false;
}
}
Taking the DIGIT DIGIT . DIGIT
example:
Pattern
class.DIGIT
, DIGIT
, .
, DIGIT
}..
will be an instance of Simple
.DIGIT
will be an instance of
Group
, which will store
1
,2
,3
,4
,5
,6
,7
,8
,9
,0
in its internal set
Simple
.matches()
will work using chain
of responsibility - delegating the
responsibility down the chain.Using this design, you can also easily define ALPHANUM
as a Group
whose internal set comprises of ALPHABETS
and DIGIT
and matches()
will still work.
Note: I coded the code here directly, so it may have typos or small errors. I omitted the constructors for better readability.
Upvotes: 0
Reputation: 62769
char[] is untyped and maybe not the best thing to interact with.
Group[] is not really very descriptive of what it does.
Perhaps you could have an interface with the method "match" and stick a bunch of objects that implement this interface in there.
So one of these objects might be instantiated "new MatchChar('a')" while another might be "new MatchType(MatchType.CAPS)".
The problem with this is that it's not very easy to instantiate--it's verbose. I would use a method (Say inside "Match" which could be a superclass of MatchType and MatchChar) like getMatches that would take a string and return your array, completely generated.
I like that your "Language" is generally more explicit than Regex, so what about something like this: "[DIGIT][DIGIT].[DIGIT]" or "[CAPS]pple"--plus the obligatory "[[]" and "[]]" to match braces.
Then your method just looks for matching [] in the string, creates the correct MatchGroup objects, turns the remaining letters into MatchChar objects and returns them to the caller.
Parsing a string like this is pretty easy, in fact StringTokenizer would have a ball with it.
Upvotes: 0
Reputation: 16265
If you want a hybrid array or collection, you are going to need to abstract char/Character and Group behind a common interface or supertype. Given that char is a primitive and Character is a final class, writing an Interface and wrapping char/Character is going to be your best bet.
I'd suggest making Group an Interface (possibly renaming it) and then create two classes that implement Group - one that wraps a char or Character (let's call it, SingleChar), and a concrete Group (let's call it GroupImpl, for now) that serves the purpose of the original group. Create an array of Group[] and manipulate each instance of Group through your common interface.
Upvotes: 1
Reputation: 116266
You could define a common superclass (interface), with subclasses for both normal characters and character classes/groups.
Upvotes: 3
Reputation: 75906
You can't define an array with elements from one of two unrelated types.
You can define your own supertype (or interface) from which you extend two classes, one that wraps a character, the other your Group.
Or, perhaps easier, just uses a Object[] and wrap that with a class that has the intelligence to put/get the correct types.
Upvotes: 0