private int consumeHeuristicExact(int start) {
        int curPos = -1;
        int actualStart = -1;
        int starPos = -1;
        int endLimit = source.length();

        boolean suffStar = false;
        boolean isQuoted = false;
        boolean seenSome = false;

        boolean wantStartQuote = true;
        boolean wantEndQuote = false;
        boolean wantStartStar = true;

        // ignore whitespace at start until we something else
        boolean ignWS = true;

        for (curPos = start; curPos < endLimit; curPos++) {
            char c = source.charAt(curPos);

            if (Character.isWhitespace(c)) {
                if (ignWS) continue;
                // ends exact token unless quoted
                if (!wantEndQuote) break;
            }
            ignWS = false;

            if (c == '"') {
                if (wantStartQuote) {
                    // starts actual token
                    wantStartQuote = false;
                    wantEndQuote = true;
                    actualStart = curPos+1;
                } else if (wantEndQuote && looksLikeExactEnd(curPos+1)) {
                    seenSome = true;
                    wantEndQuote = false;
                    isQuoted = true;
                    // ends token
                    break;
                }
                // else: part of exact token
                continue;
            }
            // no processing of non-quotes inside quotes
            if (wantEndQuote) continue;

            if (c == '*' || c == '\uFF0A') {
                if (wantStartStar) {
                    suffStar = true;
                    wantStartStar = false;
                    starPos = curPos;
                    continue;
                }
            }

            if (c == '!' || c == '*' || c == '\uFF0A') {
                // ends token if non-empty
                if (seenSome && looksLikeExactEnd(curPos)) break;
            }

            if (c == ')' && seenSome && looksLikeExactEnd(curPos)) {
                break;
            }
            if (!seenSome) {
                // everything else: something that starts the actual token
                actualStart = curPos;
                seenSome = true;
                wantStartQuote = false;
                wantStartStar = false;
            }
        }

        int end = curPos;

        // handle some ill-formed inputs:

        if (wantEndQuote) {
            // missing end quote: reprocess without quote handling
            isQuoted = false;
            actualStart = -1;
            starPos = -1;
            suffStar = false;
            seenSome = false;
            wantStartStar = true;

            // ignore whitespace at start until we something else
            ignWS = true;

            for (curPos = start; curPos < endLimit; curPos++) {
                char c = source.charAt(curPos);

                if (Character.isWhitespace(c)) {
                    if (ignWS) continue;
                    // ends exact token
                    break;
                }
                ignWS = false;

                if (c == '*' || c == '\uFF0A') {
                    if (wantStartStar) {
                        suffStar = true;
                        wantStartStar = false;
                        starPos = curPos;
                        continue;
                    }
                }

                if (c == '!' || c == '*' || c == '\uFF0A') {
                    // ends token if non-empty
                    if (seenSome) break;
                }

                if (c == ')' && seenSome && parensToEat > 0) {
                    break;
                }
                if (!seenSome) {
                    // everything else: something that starts the actual token
                    actualStart = curPos;
                    seenSome = true;
                    wantStartStar = false;
                }
            }
            end = curPos;
        }

        if (! seenSome) {
            // no token content: may need to include stars or whitespace
            if (suffStar) {
                // use the star as token:
                suffStar = false;
                actualStart = starPos;
            } else {
                // just include all we have (possibly whitespace or an empty string):
                actualStart = start;
            }
        }

        if (suffStar) {
            addToken(STAR, "*", starPos, starPos + 1);
        }
        tokens.add(new Token(WORD, source.substring(actualStart, end), true, new Substring(actualStart, end, source)));

        // skip terminating quote
        if (isQuoted) {
            end++;
        }
        return end;
    }
Resets this tokenizer and create tokens from the given string.

@param string the string to tokenize
@param defaultIndexName the name of the index to use as default
@param indexFacts information about the indexes we will search
@return a read-only list of tokens. This list can only be used by this thread
container-search/src/main/java/com/yahoo/prelude/query/parser/Tokenizer.java