如果bReturnTokens=true,把子串中的分隔符数量乘以2,再从实际总数量减去该数字,就得到了标记的总数。理由是,对于子串buy, a, book,StringTokenizer将返回5个标记(即buy:,:a:,:book),而PowerfulTokenizer将返回一个标记(即buy, a, book),两者的差值是4(即,2乘以子串中的分隔符数量)。这个公式对于所有包含分隔符的子串都有效。
类似地,对于bReturnTokens=false的情形,我们从实际总数(19)减去表达式[分隔符总数(11)- 连续分隔符数量(4) + 子串中的分隔符数量(3)]。由于这时我们不返回分隔符,它们(非连续出现或在子串内部)对我们来说没有用,上面的公式为我们返回了标记的总数量(9)。
请记住这两个公式,它们是PowerfulTokenizer的核心。这两个公式适用于几乎所有它们各自条件下的情形。但是,如果你有更复杂的要求,不能使用这两个公式,那么你应该在编写代码之前分析各种可能出现的情况,并设计出自己的公式。
// 检查分隔符是否位于子串之内
for (int i=1; i/td> { iIndex = sInput.indexOf(sDelim, iIndex+1); if (iIndex == -1) break; // 如果分隔符位于子串之内,则向前分析直至子串结束 while (sInput.substring(iIndex-iLen, iIndex).equals(sDelim)) { iNextIndex = sInput.indexOf(sDelim, iIndex+1); if (iNextIndex == -1) break; iIndex = iNextIndex; } aiIndex[i] = iIndex; //System.out.println("aiIndex[" + i + "] = " + iIndex); if (isWithinQuotes(iIndex)) { if (bIncludeDelim) iTokens -= 2; else iTokens -= 1; } }
countTokens()方法检查子串是否包含双引号。如果包含,那么它减少总数并把索引值修改为字符串中下一个双引号出现的位置(如上面的代码片断所示)。如果bReturnTokens是false,那么它从总数减去输入字符串中出现的非连续分隔符的数量。
// 如发现多个连续的分隔符,则返回""作为标记
if ( (sPrevToken.equals(sDelim)) && (sToken.equals(sDelim)) ) { sPrevToken = sToken; iTokenNo++; return ""; } // 检查标记本身是否等于分隔符 if ( (sToken.trim().startsWith("\"")) && (sToken.length() == 1) ) { // 标记本身等于分隔符的特殊情况 String sNextToken = oTokenizer.nextToken(); while (!sNextToken.trim().endsWith("\"")) { sToken += sNextToken; sNextToken = oTokenizer.nextToken(); } sToken += sNextToken; sPrevToken = sToken; iTokenNo++; return sToken.substring(1, sToken.length()-1); } // 检查字符串中是否包含子串 else if ( (sToken.trim().startsWith("\"")) && (!((sToken.trim().endsWith("\"")) && (!sToken.trim().endsWith("\"\"")))) ) { if (oTokenizer.hasMoreTokens()) { String sNextToken = oTokenizer.nextToken(); // 检查"\"\"" while (!((sNextToken.trim().endsWith("\"")) && (!sNextToken.trim().endsWith("\"\""))) ) { sToken += sNextToken; if (!oTokenizer.hasMoreTokens()) { sNextToken = ""; break; } sNextToken = oTokenizer.nextToken(); } sToken += sNextToken; } } nextToken()方法通过StringTokenizer.nextToken方法获取标记,并检查标记中的双引号字符。如果发现了这些字符,它继续获取标记直至不能再找到带有双引号的标记。另外,它还把标记保存到一个变量(sPrevToken,参见本文后面完整的源代码)以检查连续出现的分隔符。如果nextToken()发现等同于分隔符的连续多个标记,那么它返回""(长度为0的字符串)作为标记。
按照类似的方法,hasMoreTokens()方法检查已经返回的标记数量是否小于标记的总数量。
【结束语】本文为你介绍了如何轻松地编写一个强大的字符串分解器。根据本文介绍的原理,你能够迅速编写出复杂的字符串分解器,节省大量的开发时间。
|