【问题标题】:How can I replace non-printable Unicode characters in Java?如何替换 Java 中不可打印的 Unicode 字符?
【发布时间】:2011-09-06 03:20:36
【问题描述】:

以下内容将替换 ASCII 控制字符([\x00-\x1F\x7F] 的简写):

my_string.replaceAll("\\p{Cntrl}", "?");

以下内容将替换所有 ASCII 不可打印字符([\p{Graph}\x20] 的简写),包括重音字符:

my_string.replaceAll("[^\\p{Print}]", "?");

但是,它们都不适用于 Unicode 字符串。有没有人有从 unicode 字符串中删除不可打印字符的好方法?

【问题讨论】:

标签: java string unicode


【解决方案1】:
my_string.replaceAll("\\p{C}", "?");

查看更多关于Unicode regexjava.util.regexPattern/String.replaceAll 支持他们。

【讨论】:

  • 至少在 java 1.6 中,不支持它们。 download.oracle.com/javase/6/docs/api/java/util/regex/… ...我也试过你的台词,除了缺少反斜杠之外,它显然根本不起作用。
  • 这有效:char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?"); 也在 Unicode 支持 部分的模式查找的 javadoc 中,说它支持类别
  • 还有一些不可见的空白字符(如 0x0200B),它们是 \p{Zs} 组的一部分。不幸的是,这个也包括正常的空格。对于那些试图过滤不应该包含任何空格的输入字符串的人,字符串s.replaceAll("[\\p{C}\\p{Z}]", "") 将起到魅力
  • 这就是我要找的,我正在尝试replaceAll("[^\\u0000-\\uFFFF]", ""),但没有成功
  • 注意:这里介绍的这个解决方案(有 150 个赞成票)还删除了您可能不想被替换的换行符。
【解决方案2】:

Op De Cirkel 大体上是对的。他的建议在大多数情况下都会奏效:

myString.replaceAll("\\p{C}", "?");

但如果myString 可能包含非 BMP 代码点,那么它会更复杂。 \p{C} 包含 \p{Cs} 的代理代码点。上述替换方法有时会仅替换一半代理对,从而破坏非 BMP 代码点。这可能是 Java 错误而不是预期行为。

使用其他组成类别是一种选择:

myString.replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "?");

但是,不属于一对的单独代理字符(每个代理字符都有一个分配的代码点)将不会被删除。非正则表达式方法是我知道正确处理\p{C} 的唯一方法:

StringBuilder newString = new StringBuilder(myString.length());
for (int offset = 0; offset < myString.length();)
{
    int codePoint = myString.codePointAt(offset);
    offset += Character.charCount(codePoint);

    // Replace invisible control characters and unused code points
    switch (Character.getType(codePoint))
    {
        case Character.CONTROL:     // \p{Cc}
        case Character.FORMAT:      // \p{Cf}
        case Character.PRIVATE_USE: // \p{Co}
        case Character.SURROGATE:   // \p{Cs}
        case Character.UNASSIGNED:  // \p{Cn}
            newString.append('?');
            break;
        default:
            newString.append(Character.toChars(codePoint));
            break;
    }
}

【讨论】:

    【解决方案3】:

    您可能对Unicode categories "Other, Control"可能 "Other, Format" 感兴趣(不幸的是后者似乎同时包含不可打印和可打印字符)。

    在 Java 正则表达式中,您可以分别使用 \p{Cc}\p{Cf} 来检查它们。

    【讨论】:

    • 好吧,太糟糕了 java 表达式没有它们,但至少我现在得到了列表......总比没有好。谢谢
    【解决方案4】:

    以下方法可实现您的目标

    public static String removeNonAscii(String str)
    {
        return str.replaceAll("[^\\x00-\\x7F]", "");
    }
    
    public static String removeNonPrintable(String str) // All Control Char
    {
        return str.replaceAll("[\\p{C}]", "");
    }
    
    public static String removeSomeControlChar(String str) // Some Control Char
    {
        return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
    }
    
    public static String removeFullControlChar(String str)
    {
        return removeNonPrintable(str).replaceAll("[\\r\\n\\t]", "");
    } 
    

    【讨论】:

      【解决方案5】:

      我为此使用了这个简单的函数:

      private static Pattern pattern = Pattern.compile("[^ -~]");
      private static String cleanTheText(String text) {
          Matcher matcher = pattern.matcher(text);
          if ( matcher.find() ) {
              text = text.replace(matcher.group(0), "");
          }
          return text;
      }
      

      希望这是有用的。

      【讨论】:

        【解决方案6】:

        根据 Op De Cirkelnoackjr 的回答,以下是我对一般字符串清理所做的工作:1. 修剪前导或尾随空格,2. dos2unix , 3. mac2unix, 4. 删除除空格之外的所有“不可见的Unicode字符”:

        myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&amp;&amp;[^\\s]]", "")

        使用 Scala REPL 测试。

        【讨论】:

          【解决方案7】:

          我建议它删除下面的不可打印字符而不是替换它

          private String removeNonBMPCharacters(final String input) {
              StringBuilder strBuilder = new StringBuilder();
              input.codePoints().forEach((i) -> {
                  if (Character.isSupplementaryCodePoint(i)) {
                      strBuilder.append("?");
                  } else {
                      strBuilder.append(Character.toChars(i));
                  }
              });
              return strBuilder.toString();
          }
          

          【讨论】:

            【解决方案8】:

            支持的多语言

            public static String cleanUnprintableChars(String text, boolean multilanguage)
            {
                String regex = multilanguage ? "[^\\x00-\\xFF]" : "[^\\x00-\\x7F]";
                // strips off all non-ASCII characters
                text = text.replaceAll(regex, "");
            
                // erases all the ASCII control characters
                text = text.replaceAll("[\\p{Cntrl}&&[^\r\n\t]]", "");
            
                // removes non-printable characters from Unicode
                text = text.replaceAll("\\p{C}", "");
            
                return text.trim();
            }
            

            【讨论】:

              【解决方案9】:

              我重新设计了电话号码 +9 (987) 124124 的代码 Extract digits from a string in Java

               public static String stripNonDigitsV2( CharSequence input ) {
                  if (input == null)
                      return null;
                  if ( input.length() == 0 )
                      return "";
              
                  char[] result = new char[input.length()];
                  int cursor = 0;
                  CharBuffer buffer = CharBuffer.wrap( input );
                  int i=0;
                  while ( i< buffer.length()  ) { //buffer.hasRemaining()
                      char chr = buffer.get(i);
                      if (chr=='u'){
                          i=i+5;
                          chr=buffer.get(i);
                      }
              
                      if ( chr > 39 && chr < 58 )
                          result[cursor++] = chr;
                      i=i+1;
                  }
              
                  return new String( result, 0, cursor );
              }
              

              【讨论】:

                猜你喜欢
                • 2012-07-20
                • 1970-01-01
                • 2018-10-21
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-12-06
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多