Language
String: 見た目が同じUnicode文字列でもequalsが異なる
合成済み文字と結合文字の列は、表示が同じでも別のコードポイント列として比較されます。
SourceUnicodeNormalization.java
Java 21
package examples.string;
import java.text.Normalizer;
public final class UnicodeNormalization {
private UnicodeNormalization() {}
public static String nfc(String value) {
return Normalizer.normalize(value, Normalizer.Form.NFC);
}
}TestUnicodeNormalizationTest.java
Java 21
package examples.string;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import org.junit.jupiter.api.Test;
class UnicodeNormalizationTest {
@Test
void 見た目が同じでも合成済みと結合文字の文字列はequalsで異なる() {
String composed = "é";
String decomposed = "e\u0301";
assertNotEquals(composed, decomposed);
assertEquals(UnicodeNormalization.nfc(composed), UnicodeNormalization.nfc(decomposed));
}
}01Assertion
このテストで確認できること
- 合成済みのéとe+結合アクセントはequalsで異なる
- 両方をNFC正規化すると同じ文字列になる
外部入力や識別子としてUnicode文字列を比較・保存する場合は、必要な境界で正規化方針を決めます。
OBSERVED RESULT
expected: composed.equals(decomposed) → false
actual: false
expected: NFC後のequals → true
actual: true