/* Assume In.java has been downloaded to this directory
* URL for file and documentation: http://www.cs.princeton.edu/introcs/stdlib/In.java.html
* (save it in the directory that contains this program)
*/
/** An instance holds a text with lie spans delimited */
public class LieData {
/** lie spans in text are demarcated by matching spanStart/spanEnd pairs.
* text is all lowercase, with no embedded spans.
* spanStart and spanEnd must not be super- or substrings of each other,
* and must be at least one character long (once initialized).
*/
private String text;
private String spanStart;
private String spanEnd;
/** Constructor: a LieData whose text's lies are assumed to be delimited by
* and .
* Preconditions: source is the name of a file containing all lower-case
* text and containing at least one character but no embedded spans.
*/
public LieData(String sourceFile) {
text= (new In(sourceFile)).readAll();
spanStart= "";
spanEnd= "";
}
/** Constructor: a LieData whose text's lies are delimited by
* matching spanStart and spanEnd pairs.
* Preconditions: source is the name of a file containing all lower-case
* text and containing at least one character but no embedded spans.
* spanStart and spanEnd must not be super- or substrings of each other,
* and must be at least one character long.
*/
public LieData(String sourceFile, String spanStart, String spanEnd) {
text= (new In(sourceFile)).readAll();
this.spanStart= spanStart;
this.spanEnd= spanEnd;
}
/** = a TallyPair whose hits (respectively misses) are the number of non-overlapping
* occurrences of w in text within a span (respectively not within a span)
* starting at i (if i >= text.length(), the TallyPair will have 0 hits and misses).
* Preconditions: none of w, spanStart, and spanEnd are super/substrings of one of the others;
* text and w both contain at least one character
* and are all lowercase; i >= 0.
*/
// Note that this method is private, because it's a helper function
private TallyPair countsFrom(String w, int i) {
if (i >= text.length()) { // first base case
return new TallyPair(); // 0 hits and misses
}
int iW= text.indexOf(w, i);
if (iW == -1) { // second base case
return new TallyPair(); // 0 hits and misses
}
// get counts for part of text AFTER w at iW
TallyPair p= countsFrom(w,iW+w.length());
if (isHit(w,iW)) {
p.hits= p.hits+1;
} else {
p.misses= p.misses+1;
}
return p;
}
/** = a String of the form "hits: h; misses: m", where h (respectively m)
* is the number of non-overlapping occurrences of w inside (respectively outside) delimited spans
* in the text this LieFile stores.
* Precondition: w is not a superstring or substring of either span delimiter,
* and contains at least one character, and is all lowercase;
* the text from the source file is all lowercase, contains at least one character,
* no embedded spans.
*/
public String counts(String w) {
TallyPair totalCounts= countsFrom(w, 0);
return totalCounts.toString();
}
/** = "w at index iW in text is a hit (in a span)"
* Precondition: iW is an index of an instance of w in text */
// needs to be made public to use JUnit testing cases
private boolean isHit(String w, int iW) {
// get index of closest spanEnd to the right of w
int iEnd= text.indexOf(spanEnd, iW+w.length());
// = "there is such a spanEnd and its matching spanStart
// is before iW, so iW is in a span."
return iEnd != -1 &&
text.lastIndexOf(spanStart, iEnd) < iW;
}
}