关于CharMatcher.WHITESPACE实现

当我查找CharMatcher的实现并注意一个字段WHITESPACE_MULTIPLIER=1682554634 ,我将此值设置为1582554634 ,运行测试用例CharMatcherTest#testWhitespaceBreakingWhitespaceSubset ,当然它失败了。

之后,我将testWhitespaceBreakingWhitespaceSubset更改为仅在没有断言的情况下调用WHITESPACE.apply((char)c) ,在WHITESPACE.matches的方法中打印索引

 int index=(WHITESPACE_MULTIPLIER * c) >>> WHITESPACE_SHIFT) 

终于发现该指数在将WHITESPACE_MULTIPLIER1682554634更改为WHITESPACE_MULTIPLIER后发生了碰撞

毫无疑问,1682554634设计得很好,我的问题是如何推断这个“神奇数字”

根据Martin Grajcar的提议 ,我尝试按如下方式编写“幻数生成器”并进行工作:

 char[] charsReq = WHITESPACE_TABLE.toCharArray(); Arrays.sort(charsReq); OUTER: for (int WHITESPACE_MULTIPLIER_WANTTED = 1682553701; WHITESPACE_MULTIPLIER_WANTTED <= 1682554834; WHITESPACE_MULTIPLIER_WANTTED++) { int matchCnt = 0; for (int c = 0; c >> WHITESPACE_SHIFT); if (position >= 0 && index == c) { matchCnt++; } else if (position < 0 && index != c) { matchCnt++; } else { continue OUTER; } } // all valid if ((matchCnt - 1) == (int) (Character.MAX_VALUE)) { System.out.println(WHITESPACE_MULTIPLIER_WANTTED); } } 

如果在WHITESPACE_TABLE中更改了字符序列(swap \ u2001 \ u2002位置),则算法没有解决方案(将循环结束条件更改为Integer.MAX_VALUE)。

因为IntMath.gcd实现是指http://en.wikipedia.org/wiki/Binary_GCD_algorithm
我的问题是在哪里可以找到CharMatcher.WHITESPACE.match实现的材料?

我不确定生成器是否仍然存在于某个地方,但它可以轻松地重新创建。 Result类包含CharMatcher.WHITESPACE实现中使用的数据:

 static class Result { private int shift; private int multiplier; private String table; } // No duplicates allowed. private final String allMatchingString = "\u2002\r\u0085\u200A\u2005\u2000" + "\u2029\u000B\u2008\u2003\u205F\u1680" + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" + "\u2004\u2028\n\u2007\u3000"; public Result generate(String allMatchingString) { final char[] allMatching = allMatchingString.toCharArray(); final char filler = allMatching[allMatching.length - 1]; final int shift = Integer.numberOfLeadingZeros(allMatching.length); final char[] table = new char[1 << (32 - shift)]; OUTER: for (int i=0; i>=0; ++i) { final int multiplier = 123456789 * i; // Jumping a bit makes the search faster. Arrays.fill(table, filler); for (final char c : allMatching) { final int index = (multiplier * c) >>> shift; if (table[index] != filler) continue OUTER; // Conflict found. table[index] = c; } return new Result(shift, multiplier, new String(table)); } return null; // No solution exists. } 

它会产生不同的乘数,但这并不重要。

如果不存在给定allMatchingString解决方案,您可以减少shift并再次尝试。