【问题标题】:Filtering non MySQL Latin1 Characters from a String in Java从 Java 中的字符串中过滤非 MySQL Latin1 字符
【发布时间】:2019-02-25 20:32:22
【问题描述】:

我有一个使用 latin1 的 MySQL 表,很遗憾我无法更改它。

在将字符串插入此表之前,我想检查字符串是否包含不属于 latin1 字符集的字符。这样我就可以将它从我的数据集中删除。

我该怎么做?

例如

boolean hasNonLatin1Chars = string.chars()
                .anyMatch(c -> ...)

【问题讨论】:

    标签: java mysql utf-8 iso-8859-1


    【解决方案1】:

    为了保持简单和健壮,请利用CharsetEncoder

    /** replaces any invalid character in Latin1 by the character rep */
    public static String latin1(String str, char rep) {
        CharsetEncoder cs = StandardCharsets.ISO_8859_1.newEncoder()
                .onMalformedInput(CodingErrorAction.REPLACE)
                .onUnmappableCharacter(CodingErrorAction.REPLACE)
                .replaceWith(new byte[] { (byte) rep });
        try {
            ByteBuffer b = cs.encode(CharBuffer.wrap(str));
            return new String(b.array(), StandardCharsets.ISO_8859_1);
        } catch (CharacterCodingException e) {
            throw new RuntimeException(e); // should not happen
        }
    }
    

    这会将 ISO_8859_1 (= Latin1) 中的每个无效字符集替换为替换字符 rep(当然,它应该是一个有效的 Latin1 字符)。

    如果你对默认替换('?')没问题,你可以让它更简单:

    public static String latin1(String str) {
        return new String(str.getBytes(StandardCharsets.ISO_8859_1),
              StandardCharsets.ISO_8859_1);
    }
    

    例如:

    public static void main(String[] args)  {
        String x = "hi Œmar!";
        System.out.println("'" + x + "' -> '" + latin1(x,'?') + "'");
    }
    

    输出'hi Œmar!' -> 'hi ?mar!'

    这种方法的一个可能缺点是只允许您用单个替换字符替换每个无效字符 - 您不能删除它或使用多字符序列。 如果你想要这个,并且如果你有理由确定某些字符永远不会出现在你的字符串中,你可以采用通常的肮脏技巧 - 例如,假设 \u0000 永远不会出现:

    /* removes invalid Latin1 charaters - assumes the zero character never appears */
    public static String latin1removeinvalid(String str) {
        return latin1(str,(char)0).replace("\u0000", "");
    }
    

    补充:如果你只想检查有效性,那就更简单了:

    public static boolean isValidLatin1(String str) {
        return StandardCharsets.ISO_8859_1.newEncoder().canEncode(str);
    }
    

    【讨论】:

    • 谢谢,效果很好。我真的只需要解决 if 有无效字符,但我可以像其他答案一样事后进行相等性检查:)
    • @Edd :如果您只想检查有效性,那么它更简单 - 请参阅更新
    【解决方案2】:

    如果您的源数据始终是 UTF8,那么就这么说吧。然后,您将获得两全其美的效果——音译为 latin1 的 UTF8 字符将被更改;那些不出来的会显示为“?”。

    getConnection() 调用中使用它:

    ?useUnicode=yes&characterEncoding=UTF-8
    

    不测试坏字符,不转换代码。 MySQL 自动完成所有工作。

    【讨论】:

      【解决方案3】:

      Basic Latin range0020–007F,因此您可以检查尝试替换非拉丁字符的第一个实例是否与原始 String 匹配:

      boolean hasNonLatin1Chars = string.equals((string.replaceFirst("[^\\u0020-\\u007F]", "")));
      

      如果它包含非拉丁字符,这将返回 false

      有 Latin-1 Supplement (00A0 — 00FF)、Latin Extended-A (0100 — 017F) 和 Latin Extended-B (0180 — 024F),因此您可以根据需要修改范围。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-05
        • 2013-06-14
        • 2011-11-02
        • 2015-04-15
        • 2013-04-13
        • 2011-02-23
        • 2013-08-12
        • 2017-02-02
        相关资源
        最近更新 更多