squidpony.ObText Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of squidlib-util Show documentation
Show all versions of squidlib-util Show documentation
SquidLib platform-independent logic and utility code. Please refer to
https://github.com/SquidPony/SquidLib .
package squidpony;
import regexodus.Matcher;
import regexodus.Pattern;
import regexodus.REFlags;
import squidpony.annotation.Beta;
import squidpony.squidmath.*;
import java.io.Reader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static squidpony.ArrayTools.letters;
/**
* A simple format parser for String-based configuration or data files where JSON is overkill.
* Supports only one type, String, but allows each String to have arbitrary nested levels of
* String children as if in sub-lists. You can interpret the Strings however you want, and
* quoting each String isn't necessary if they are just one word ("bare words" are allowed).
* This stores its items in an inner class, {@link ObTextEntry}, which only has a "primary"
* String and may have a List of "associated" ObTextEntry values, each of which must have
* their own primary String and which may have their own associated List.
*
* You can use this like any other List, though it will be contain ObTextEntry objects instead
* of Strings directly. This allows you to control whether you want to iterate through a
* particular primary String's associated entries, if there are any, or to skip over them and
* go to the next String in the current List.
*
* This implements List of String and is modifiable; it extends the List interface with
* {@link #parse(CharSequence)} to read a String in the following format, as well as with some
* overloads of add() to add just a String with no associated values. A quirk of how this
* implements List is that it only considers the top-level Strings to be part of the List for
* length and for {@link #contains(Object)}, and will ignore child strings unless you access
* them via the {@link ObTextEntry#associated} List on an entry that has associated entries.
*
* Format example:
*
* hello world
* 'how are you today?' [just great thanks]
* hooray!
*
* complexity?
* [it is possible [yes this is a good example]
* 'escapes like \[\'\] all work'
* "you can use double or single quotes to allow spaces and brackets in one string"
* ]
*
* comments are allowed // like this
* comments can have different forms # like this
* // block comments like in c are allowed
* / * but because this example is in javadoc, this example is not actually a comment * /
* // remove the spaces between each slash and asterisk to make the last line a comment.
* /[delimit/or block comments with delimiters/delimit]/
*
* '''
* raw strings (heredocs) look like this normally.
* they permit characters without escapes, ]][][[ \/\/\ ,
* except for triple quotes.
* they keep newlines and indentation intact,
* except for up to one newline ignored adjacent to each triple quote.
* '''
*
* [[different[
* if you may need triple quotes
* in the raw string, use a different syntax that allows delimiters.
* here, the delimiter is '''different''', just to be different.]different]]
*
*
* Inspired strongly by STOB, https://github.com/igagis/stob-java and https://github.com/igagis/stob , but
* no code is shared and the format is slightly different. The main differences are:
*
* - We use square brackets in place of STOB's curly braces to mark children associated with a string.
-
*
- ObText supports nested block comments using the syntax {@code /[delimiter/contents/delimiter]/} where
* delimiter may be empty but must match on both sides, and contents is the body of the comment.
* - ObText uses Python-like "heredoc" syntax for raw strings surrounded by triple-apostrophes '''like so'''
* with optional initial and final newlines in the raw string ignored. An alternate raw string
* syntax is present that allows delimiters, using the syntax {@code [[delimiter[contents]delimiter]]}, where
* again delimiter may be empty and contents is the body of the raw string.
*
*/
@Beta
public class ObText extends ArrayList implements Serializable{
private static final long serialVersionUID = 7L;
public static class ObTextEntry implements Serializable
{
private static final long serialVersionUID = 7L;
public String primary;
public ArrayList associated;
public ObTextEntry()
{
}
public ObTextEntry(String primaryString)
{
primary = primaryString;
}
public ObTextEntry(String primaryString, Collection associatedStrings)
{
primary = primaryString;
associated = new ArrayList<>(associatedStrings);
}
public void add(ObTextEntry entry)
{
if(associated == null)
associated = new ArrayList<>(16);
associated.add(entry);
}
public void add(String text)
{
if(associated == null)
associated = new ArrayList<>(16);
associated.add(new ObTextEntry(text));
}
public boolean hasAssociated()
{
return associated != null && !associated.isEmpty();
}
public List openAssociated()
{
if(associated == null)
associated = new ArrayList<>(16);
return associated;
}
public String firstAssociatedString()
{
ObTextEntry got;
if(associated == null || associated.isEmpty() || (got = associated.get(0)) == null)
return null;
return got.primary;
}
public ArrayList allAssociatedStrings()
{
if(associated == null || associated.isEmpty())
return new ArrayList<>(1);
int sz = associated.size();
ArrayList strings = new ArrayList<>(sz);
for (int i = 0; i < sz; i++) {
strings.add(associated.get(i).primary);
}
return strings;
}
public ArrayList shallowContents()
{
if(associated == null || associated.isEmpty())
return new ArrayList<>(1);
int sz = associated.size();
ArrayList strings = new ArrayList<>(sz);
iterate(strings, associated);
return strings;
}
public ObTextEntry firstAssociatedEntry()
{
if(associated == null || associated.isEmpty())
return null;
return associated.get(0);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ObTextEntry entry = (ObTextEntry) o;
if (!primary.equals(entry.primary)) return false;
return associated != null ? associated.equals(entry.associated) : entry.associated == null;
}
public long hash64() {
long result = CrossHash.hash64(primary), z = 0x60642E2A34326F15L;
if(associated == null)
return result ^ z;
final int len = associated.size();
for (int i = 0; i < len; i++) {
result ^= (z += (associated.get(i).hash64() ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL);
result = (result << 54 | result >>> 10);
}
result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L;
result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL;
return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L);
}
@Override
public int hashCode() {
return (int)hash64();
}
}
public static final Pattern pattern = Pattern.compile(
"(?>'''(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?({=s}.*?)(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?''')" +
"|(?>\\[\\[({=q}[^\\[\\]]*)\\[(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?({=s}.*?)(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?\\]{\\q}\\]\\])" +
"|(?>({=q}[\"'])({=s}.*?)(?(?>//|#)(?>\\V*))" +
"|(?>/\\*(?:.*?)\\*/)" +
"|(?>/\\[({=q}\\S*)/(?:.*?)/{\\q}\\]/)" +
"|({=s}[^\\s\\[\\]\"'#\\\\]+)" +
"|({=o}\\[)" +
"|({=c}\\])", REFlags.DOTALL | REFlags.UNICODE
),
patternRelaxed = Pattern.compile(
"(?>'''(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?({=s}.*?)(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?''')" +
"|(?>\\[\\[({=q}[^\\[\\]]*)\\[(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?({=s}.*?)(?:[\n\u000C\f\r\u0085\u2028\u2029]|\r\n)?\\]{\\q}\\]\\])" +
"|(?>({=q}[\"'])({=s}.*?)(?(?>//|#)(?>\\V*))" +
//"|(?>/\\*(?:.*?)\\*/)" +
//"|(?>/\\[({=q}\\S*)/(?:.*?)/{\\q}\\]/)" +
"|({=s}[^\\s\\[\\]\"'\\\\]+)"
, REFlags.DOTALL | REFlags.UNICODE
);
public static final int stringId = pattern.groupId("s"),
openId = pattern.groupId("o"), closeId = pattern.groupId("c");
protected static final Pattern illegalBareWord = Pattern.compile("[\\s\\[\\]\"'#\\\\]|(?:/[/\\*])"),
reallyIllegalBareWord = Pattern.compile("[\\s\\[\\]\"'\\\\]"),
needsRaw = Pattern.compile("(? entries = new ArrayList(64);
// protected final IntVLA neighbors = new IntVLA(64);
// private final IntVLA nesting = new IntVLA(16);
// protected int length = 0;
public ObText()
{
}
public ObText(CharSequence text)
{
parse(text);
}
/**
* Parses the given text (a String or other CharSequence) and appends it into this ObText.
* @param text a CharSequence (such as a String) using ObText formatting, as described in this class' JavaDocs
* @return this ObText object after appending the parsed text, for chaining
*/
public ObText parse(CharSequence text)
{
m.setTarget(text);
ObTextEntry current = null;
List ls = this;
IntVLA nesting = new IntVLA(4);
nesting.add(-1);
int depth = 0;
while (m.find()) {
if (m.isCaptured(stringId)) {
ls.add(current = new ObTextEntry(m.group(stringId)));
nesting.incr(depth, 1);
}
else if(m.isCaptured(openId))
{
if(current == null) throw new UnsupportedOperationException("ObText entries can't have associated items without a primary String.");
nesting.add(-1);
ls = current.openAssociated();
depth++;
}
else if(m.isCaptured(closeId))
{
if(nesting.size <= 1) throw new UnsupportedOperationException("Associated item sequences in ObText can't end more times than they start.");
nesting.pop();
depth--;
ls = this;
for (int i = 0; i < depth; i++) {
ls = ls.get(nesting.get(i)).associated;
}
}
}
return this;
}
/**
* Inserts the given String element at the specified position in this ObText's top level.
* Shifts the element currently at that position (if any) and any subsequent
* elements to the right (adds one to their indices).
* @param index index at which the specified element is to be inserted
* @param text String element to be inserted, without any associated entries
*/
public void add(int index, String text) {
super.add(index, new ObTextEntry(text));
}
/**
* Appends the given String element to the end of this ObText at the top level.
* @param text String element to be inserted, without any associated entries
* @return {@code true} (this always modifies the ObText)
*/
public boolean add(String text) {
return super.add(new ObTextEntry(text));
}
public long hash64()
{
long result = 0x1A976FDF6BF60B8EL, z = 0x60642E2A34326F15L;
final int len = size();
for (int i = 0; i < len; i++) {
result ^= (z += (get(i).hash64() ^ 0xC6BC279692B5CC85L) * 0x6C8E9CF570932BABL);
result = (result << 54 | result >>> 10);
}
result += (z ^ z >>> 26) * 0x632BE59BD9B4E019L;
result = (result ^ result >>> 33) * 0xFF51AFD7ED558CCDL;
return ((result ^ result >>> 33) * 0xC4CEB9FE1A85EC53L);
}
@Override
public int hashCode() {
return (int)hash64();
}
// Used to generate randomized delimiters using up to 9 non-English letters.
// call while assigning your state with randomChars(state += 0x9E3779B97F4A7C15L, myChars)
// that assumes you have a 9-element char[] called myChars
// as long as z/state is deterministic (i.e. based on a hash), this should be too
private static void randomChars(long z, char[] mut)
{
z = (z ^ (z >>> 30)) * 0xBF58476D1CE4E5B9L;
z = (z ^ (z >>> 27)) * 0x94D049BB133111EBL;
z ^= (z >>> 31);
mut[0] = letters[(int)(128 + (z & 127))];
mut[1] = letters[(int)(128 + (z >>> 7 & 127))];
mut[2] = letters[(int)(128 + (z >>> 14 & 127))];
mut[3] = letters[(int)(128 + (z >>> 21 & 127))];
mut[4] = letters[(int)(128 + (z >>> 28 & 127))];
mut[5] = letters[(int)(128 + (z >>> 35 & 127))];
mut[6] = letters[(int)(128 + (z >>> 42 & 127))];
mut[7] = letters[(int)(128 + (z >>> 49 & 127))];
mut[8] = letters[(int)(128 + (z >>> 56 & 127))];
}
public static void appendQuoted(StringBuilder sb, String text)
{
appendQuoted(sb, text, reallyBare);
}
public static void appendQuotedObText(StringBuilder sb, String text)
{
appendQuoted(sb, text, bare);
}
protected static void appendQuoted(StringBuilder sb, String text, Matcher bareFinder)
{
if(text == null || text.isEmpty()) {
sb.append("''");
return;
}
bareFinder.setTarget(text);
if(!bareFinder.find())
sb.append(text);
else
{
raw.setTarget(text);
if(raw.find()) {
if (text.contains("'''")) {
long state = CrossHash.hash64(text);
char[] myChars = new char[9];
int count;
do {
randomChars(state += 0x9E3779B97F4A7C15L, myChars);
count = StringKit.containsPart(text, myChars, "]", "]]");
} while (count == 12);
sb.append("[[").append(myChars, 0, count).append("[\n").append(text).append("\n]")
.append(myChars, 0, count).append("]]");
} else {
sb.append("'''\n").append(text).append("\n'''");
}
}
else if(!text.contains("'"))
{
sb.append('\'').append(text).append('\'');
}
else
{
if(text.contains("\""))
{
if(text.contains("'''"))
{
long state = CrossHash.hash64(text);
char[] myChars = new char[9];
int count;
do
{
randomChars(state += 0x9E3779B97F4A7C15L, myChars);
count = StringKit.containsPart(text, myChars);
}while(count == 9);
sb.append("[[").append(myChars, 0, count).append("[\n").append(text).append("\n]")
.append(myChars, 0, count).append("]]");
}
else
{
sb.append("'''\n").append(text).append("\n'''");
}
}
else
{
sb.append('"').append(text).append('"');
}
}
}
}
@Override
public String toString() {
return "ObText object: [[[[\n" + serializeToString() + "\n]]]]";
}
public String serializeToString()
{
StringBuilder sb = new StringBuilder(100);
iterate(sb, this);
return sb.toString();
}
/**
* Deserializes an ObText that was serialized by {@link #serializeToString()} or {@link #toString()}, and will
* ignore the prefix and suffix that toString appends for readability (these are "ObText object: [[[[ " and " ]]]]",
* for reference). This is otherwise the same as calling the constructor {@link #ObText(CharSequence)}.
* @param data a String that is usually produced by serializeToString or toString on an ObText
* @return a new ObText produced by parsing data (disregarding any prefix or suffix from toString() )
*/
public static ObText deserializeFromString(String data)
{
if(data.startsWith("ObText object: [[[[\n"))
{
return new ObText(data.substring(20, data.length() - 5));
}
return new ObText(data);
}
private static void iterate(StringBuilder sb, ArrayList obt)
{
int len = obt.size();
ObTextEntry entry;
for (int i = 0; i < len; i++) {
appendQuotedObText(sb, (entry = obt.get(i)).primary);
sb.append('\n');
if(entry.hasAssociated())
{
sb.append("[\n");
iterate(sb, entry.associated);
sb.append("]\n");
}
}
}
private static void iterate(ArrayList buffer, ArrayList obt)
{
int len = obt.size();
ObTextEntry entry;
for (int i = 0; i < len; i++) {
buffer.add((entry = obt.get(i)).primary);
if(entry.hasAssociated())
{
iterate(buffer, entry.associated);
}
}
}
/**
* Gets all Strings from the top level of this ObText, not including any associated values, and puts them in
* an {@link ArrayList} of String. The returned lisy will retain the same order the Strings were entered in, and
* unlike {@link #keySet()} or {@link #keyOrderedSet()}, duplicate keys will all be preserved. Changes to the
* returned List won't be reflected in this ObText.
* @return all top-level Strings (without associated values) as an ArrayList of String
*/
public ArrayList keyList()
{
final int sz = size();
ArrayList keys = new ArrayList<>(sz);
for (int i = 0; i < sz; i++) {
keys.add(get(i).primary);
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText, not including any associated values, and puts them in
* an {@link OrderedSet} of String. The returned set will retain the same order the Strings were entered in, and you
* can use OrderedSet methods like {@link OrderedSet#getAt(int)} to look up keys by index. Changes to the returned
* Set won't be reflected in this ObText.
* @return all unique top-level Strings (without associated values) as an OrderedSet of String keys
*/
public OrderedSet keyOrderedSet()
{
final int sz = size();
OrderedSet keys = new OrderedSet<>(sz, CrossHash.stringHasher);
for (int i = 0; i < sz; i++) {
keys.add(get(i).primary);
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText, not including any associated values, and puts them in
* an {@link UnorderedSet} of String. Although the returned set won't be insertion-ordered or necessarily retain the
* same order the Strings were entered in, the order will be the same on different JVMs, including GWT, because the
* hashing algorithm is set to one that behaves the same across JVM versions. Changes to the returned Set won't be
* reflected in this ObText.
* @return all unique top-level Strings (without associated values) as an UnorderedSet of String keys
*/
public UnorderedSet keySet()
{
final int sz = size();
UnorderedSet keys = new UnorderedSet<>(sz, CrossHash.stringHasher);
for (int i = 0; i < sz; i++) {
keys.add(get(i).primary);
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText as keys in an {@link OrderedMap}, with the first String
* associated with each key as its value (or null if nothing is associated with a key String). The returned map will
* retain the same order the keys were entered in, and you can use OrderedMap methods like
* {@link OrderedMap#keyAt(int)} to look up keys by index or {@link OrderedMap#getAt(int)} to look up value String
* by index. Changes to the returned Map won't be reflected in this ObText.
* @return an OrderedMap of unique String keys associated with the first associated String for each key (or null)
*/
public OrderedMap basicOrderedMap()
{
final int sz = size();
OrderedMap keys = new OrderedMap<>(sz, CrossHash.stringHasher);
ObTextEntry got;
for (int i = 0; i < sz; i++) {
got = get(i);
keys.put(got.primary, got.firstAssociatedString());
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText as keys in an {@link UnorderedMap}, with the first
* String associated with each key as its value (or null if nothing is associated with a key String). Although the
* returned map won't be insertion-ordered or necessarily retain the same order the Strings were entered in, the
* order will be the same on different JVMs, including GWT, because the hashing algorithm is set to one that behaves
* the same across JVM versions. Changes to the returned Map won't be reflected in this ObText.
* @return an UnorderedMap of unique String keys associated with the first associated String for each key (or null)
*/
public UnorderedMap basicMap()
{
final int sz = size();
UnorderedMap keys = new UnorderedMap<>(sz, CrossHash.stringHasher);
ObTextEntry got;
for (int i = 0; i < sz; i++) {
got = get(i);
keys.put(got.primary, got.firstAssociatedString());
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText as keys in an {@link OrderedMap}, with any Strings
* associated with those keys as their values (in a possibly-empty ArrayList of String for each value).
* The returned map will retain the same order the keys were entered in, and you can use OrderedMap methods like
* {@link OrderedMap#keyAt(int)} to look up keys by index or {@link OrderedMap#getAt(int)} to look up the ArrayList
* of value Strings by index. Changes to the returned Map won't be reflected in this ObText.
* @return an OrderedMap of unique String keys associated with ArrayList values containing associated Strings
*/
public OrderedMap> shallowOrderedMap()
{
final int sz = size();
OrderedMap> keys = new OrderedMap<>(sz, CrossHash.stringHasher);
ObTextEntry got;
for (int i = 0; i < sz; i++) {
got = get(i);
keys.put(got.primary, got.allAssociatedStrings());
}
return keys;
}
/**
* Gets all unique Strings from the top level of this ObText as keys in an {@link UnorderedMap}, with any Strings
* associated with those keys as their values (in a possibly-empty ArrayList of String for each value).
* Although the returned map won't be insertion-ordered or necessarily retain the same order the Strings were
* entered in, the order will be the same on different JVMs, including GWT, because the hashing algorithm is set to
* one that behaves the same across JVM versions. Changes to the returned Map won't be reflected in this ObText.
* @return an UnorderedMap of unique String keys associated with ArrayList values containing associated Strings
*/
public UnorderedMap> shallowMap()
{
final int sz = size();
UnorderedMap> keys = new UnorderedMap<>(sz, CrossHash.stringHasher);
ObTextEntry got;
for (int i = 0; i < sz; i++) {
got = get(i);
keys.put(got.primary, got.allAssociatedStrings());
}
return keys;
}
/**
* Can be used to help reading sequences of Strings with ObText-style quotation marking their boundaries.
* This returns a {@link ContentMatcher} object that you must call setTarget on before using it.
* The argument(s) to setTarget should be the text that might contain quotes, heredoc-style quotes, or just bare
* words. Calling {@link ContentMatcher#find()} will try to find the next String, returning false if there's nothing
* left or returning true and advancing the search if a String was found. The String might be a special term in some
* cases, like "[" and "]" without quotes being syntax in ObText that don't contain usable Strings. That's why,
* after a String was found with find(), you should check {@link ContentMatcher#hasMatch()} to verify that a match
* was successful, and if that's true, then you can call {@link ContentMatcher#getMatch()} to get the un-quoted
* contents of the next String in the target.
* @return a {@link ContentMatcher} that must have one of its setTarget() methods called before it can be used
*/
public static ContentMatcher makeMatcher()
{
return new ContentMatcher();
}
/**
* Can be used to help reading sequences of Strings with ObText-style quotation marking their boundaries.
* This returns a {@link ContentMatcher} object that is already configured to read from {@code text}.
* The {@code text} should contain Strings that may be surrounded by quotes, heredoc-style quotes, or just bare
* words. Calling {@link ContentMatcher#find()} will try to find the next String, returning false if there's nothing
* left or returning true and advancing the search if a String was found. The String might be a special term in some
* cases, like "[" and "]" without quotes being syntax in ObText that don't contain usable Strings. That's why,
* after a String was found with find(), you should check {@link ContentMatcher#hasMatch()} to verify that a match
* was successful, and if that's true, then you can call {@link ContentMatcher#getMatch()} to get the un-quoted
* contents of the next String in the target.
* @param text the target String that should probably have at least one sub-string that might be quoted
* @return a {@link ContentMatcher} that can be used immediately by calling {@link ContentMatcher#find()}
*/
public static ContentMatcher makeMatcher(CharSequence text)
{
return new ContentMatcher(text);
}
/**
* Can be used to help reading sequences of Strings with ObText-style quotation marking their boundaries, but no
* comments (which allows some additional characters to be used in bare words, like '#').
* This returns a {@link ContentMatcher} object that is already configured to read from {@code text}.
* The {@code text} should contain Strings that may be surrounded by quotes, heredoc-style quotes, or just bare
* words. Calling {@link ContentMatcher#find()} will try to find the next String, returning false if there's nothing
* left or returning true and advancing the search if a String was found. Unlike the ContentMatcher produced by
* {@link #makeMatcher(CharSequence)}, you can call {@link ContentMatcher#getMatch()} after any successful call to
* {@link ContentMatcher#find()}, which will get the un-quoted contents of the next String in the target.
* @param text the target String that should probably have at least one sub-string that might be quoted
* @return a {@link ContentMatcher} that can be used immediately by calling {@link ContentMatcher#find()}
*/
public static ContentMatcher makeMatcherNoComments(CharSequence text)
{
return new ContentMatcher(text, patternRelaxed);
}
public static class ContentMatcher extends Matcher {
/**
* Constructs a ContentMatcher that will need to have its target set with {@link #setTarget(CharSequence)} or
* one of its overloads. The target should contain multiple substrings that may have quotation around them; this
* class is meant to skip the quotation in ObText's style.
*/
public ContentMatcher()
{
super(pattern);
}
/**
* Constructs a ContentMatcher that already has its target set to {@code text}.
* @param text the CharSequence, such as a String, to find possibly-quoted Strings in.
*/
public ContentMatcher(CharSequence text)
{
super(pattern, text);
}
/**
* Constructs a ContentMatcher that already has its target set to {@code text} and uses an alternate Pattern.
*/
ContentMatcher(CharSequence text, Pattern altPattern)
{
super(altPattern, text);
}
/**
* Supplies a text to search in/match with.
* Resets current search position to zero.
*
* @param text - a data
* @see Matcher#setTarget(Matcher, int)
* @see Matcher#setTarget(CharSequence, int, int)
* @see Matcher#setTarget(char[], int, int)
* @see Matcher#setTarget(Reader, int)
*/
@Override
public void setTarget(CharSequence text) {
super.setTarget(text);
}
/**
* Supplies a text to search in/match with, as a part of String.
* Resets current search position to zero.
*
* @param text - a data source
* @param start - where the target starts
* @param len - how long is the target
* @see Matcher#setTarget(Matcher, int)
* @see Matcher#setTarget(CharSequence)
* @see Matcher#setTarget(char[], int, int)
* @see Matcher#setTarget(Reader, int)
*/
@Override
public void setTarget(CharSequence text, int start, int len) {
super.setTarget(text, start, len);
}
/**
* Supplies a text to search in/match with, as a part of char array.
* Resets current search position to zero.
*
* @param text - a data source
* @param start - where the target starts
* @param len - how long is the target
* @see Matcher#setTarget(Matcher, int)
* @see Matcher#setTarget(CharSequence)
* @see Matcher#setTarget(CharSequence, int, int)
* @see Matcher#setTarget(Reader, int)
*/
@Override
public void setTarget(char[] text, int start, int len) {
super.setTarget(text, start, len);
}
/**
* Returns true if {@link #find()} has returned true and the found text is a usable String (not some syntax).
* If this returns true, you can reasonably get a (possibly empty) String using {@link #getMatch()}.
* @return true if there is a usable String found that can be obtained with {@link #getMatch()}
*/
public boolean hasMatch()
{
return isCaptured(stringId);
}
/**
* Returns the contents of the latest String successfully found with {@link #find()}, without quotation.
* You should typically call {@link #hasMatch()} even if find() has returned true, to ensure there is a valid
* String that can be acquired (this will return an empty String if hasMatch() returns false, but an empty
* String is also potentially a valid result in a successful match, so it should be distinguished).
* @return the contents of the latest String successfully found with {@link #find()}
*/
public String getMatch()
{
return group(stringId);
}
}
}