FullHalfConverter { public String toFullwidth(String halfwidth) { if (halfwidth == null || halfwidth.isEmpty()) { return halfwidth; } StringBuilder builder = new StringBuilder(); Queue<String> buffer = new LinkedList<String>(); for (int i = 0; i < halfwidth.length(); i++) { char c = halfwidth.charAt(i); String s = String.valueOf(c); if (buffer.isEmpty()) { buffer.add(s); continue; } String prev = buffer.poll(); if (predicate.isAppendable(c)) { FullHalfPair pair = this.halfwidthMap.get(prev + s); if (pair != null) { builder.append(pair.fullwidth()); } else { builder.append(fullwidth(prev)); builder.append(fullwidth(s)); } } else { builder.append(fullwidth(prev)); buffer.add(s); } } if (!buffer.isEmpty()) { builder.append(fullwidth(buffer.poll())); } return builder.toString(); } FullHalfConverter(FullHalfPairs pairs); String toHalfwidth(String fullwidth); String toFullwidth(String halfwidth);  }
@Test public void testWithCustomAppenadablePredicate() { FullHalfConverter converter = new FullHalfConverter(new FullHalfPairsBuilder() .pair("バ", "ﾊﾞ").pair("ハ", "ﾊ").pair("゛", "ﾞ").pair("゜", "ﾟ") .appendablePredicate(new FullHalfPairs.AppendablePredicate() { @Override public boolean isAppendable(char c) { return c == 'ﾞ'; } }).build()); assertThat(converter.toFullwidth("ﾊﾞ"), is("バ")); assertThat(converter.toFullwidth("ﾊﾟ"), is("ハ゜")); }