如何从java中的字符串中删除无效的unicode字符

我正在使用CoreNLP神经网络依赖性解析器来解析一些社交媒体内容。 不幸的是,该文件包含的字符根据fileformat.info ,不是有效的unicode字符或unicode替换字符。 这些是例如U + D83D或U + FFFD 。 如果这些字符在文件中,coreNLP会回复错误消息,如下所示:

Nov 15, 2015 5:15:38 PM edu.stanford.nlp.process.PTBLexer next WARNING: Untokenizable: ? (U+D83D, decimal: 55357) 

基于这个答案,我尝试了document.replaceAll("\\p{C}", ""); 只是删除那些字符。 这里的文档只是作为字符串的文档。 但这没有帮助。

在将字符串传递给coreNLP之前,如何从字符串中删除这些字符?

更新(11月16日):

为了完整起见,我应该提一下,我只是为了通过预处理文件来避免大量的错误消息而问这个问题。 CoreNLP只是忽略它无法处理的字符,所以这不是问题。

在某种程度上, Mukesh Kumar和GsusRecovery提供的答案都有帮助,但并不完全正确。

 document.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", ""); 

似乎替换了所有无效字符。 但CoreNLP似乎不再支持。 我通过在整个语料库中运行解析器手动找出它们,这导致了这个:

 document.replaceAll("[\\uD83D\\uFFFD\\uFE0F\\u203C\\u3010\\u3011\\u300A\\u166D\\u200C\\u202A\\u202C\\u2049\\u20E3\\u300B\\u300C\\u3030\\u065F\\u0099\\u0F3A\\u0F3B\\uF610\\uFFFC]", ""); 

所以现在我在将文档交给解析器之前运行两个replaceAll()命令。 完整的代码片段是

 // remove invalid unicode characters String tmpDoc1 = document.replaceAll("[^\\u0009\\u000a\\u000d\\u0020-\\uD7FF\\uE000-\\uFFFD]", ""); // remove other unicode characters coreNLP can't handle String tmpDoc2 = tmpDoc1.replaceAll("[\\uD83D\\uFFFD\\uFE0F\\u203C\\u3010\\u3011\\u300A\\u166D\\u200C\\u202A\\u202C\\u2049\\u20E3\\u300B\\u300C\\u3030\\u065F\\u0099\\u0F3A\\u0F3B\\uF610\\uFFFC]", ""); DocumentPreprocessor tokenizer = new DocumentPreprocessor(new StringReader(tmpDoc2)); for (List sentence : tokenizer) { List tagged = tagger.tagSentence(sentence); GrammaticalStructure gs = parser.predict(tagged); System.err.println(gs); } 

但这不一定是不受支持的字符的完整列表,这就是我在GitHub上打开问题的原因。

请注意,CoreNLP会自动删除那些不受支持的字符。 我想预处理语料库的唯一原因是避免所有这些错误消息。

11月27日更新

克里斯托弗曼宁刚刚回答了我打开的GitHub问题 。 有几种方法可以使用类edu.stanford.nlp.process.TokenizerFactory;处理这些字符edu.stanford.nlp.process.TokenizerFactory; 。 以此代码示例来标记文档:

 DocumentPreprocessor tokenizer = new DocumentPreprocessor(new StringReader(document)); TokenizerFactory factory=null; factory=PTBTokenizer.factory(); factory.setOptions("untokenizable=noneDelete"); tokenizer.setTokenizerFactory(factory); for (List sentence : tokenizer) { // do something with the sentence } 

您可以将第4行中的noneDelete替换为其他选项。 我引用曼宁:

“(…)完整的六个选项组合,组合是否记录无,第一个或全部的警告,以及是否删除它们或将它们作为单个字符标记包含在输出中:noneDelete,firstDelete,allDelete, noneKeep,firstKeep,allKeep。“

这意味着,要保留字符而不获取所有这些错误消息,最好的方法是使用选项noneKeep 。 这种方式比任何删除这些字符的尝试都更优雅。

删除特定的不需要的字符:

 document.replaceAll("[\\uD83D\\uFFFD\\uFE0F\\u203C\\u3010]", ""); 

如果您发现其他不需要的字符,只需使用相同的架构添加到列表中。

更新

unicode字符由正则表达式引擎分成7个宏组(和几个子组),由一个字母(宏组)或两个字母(子组)标识。

基于你的示例和unicode类,我们认为你可以尝试一种独特的唯一良好传递方法,例如:

 document.replaceAll("[^\\p{L}\\p{N}\\p{Z}\\p{Sm}\\p{Sc}\\p{Sk}\\p{Pi}\\p{Pf}\\p{Pc}\\p{Mc}]","") 

这个正则表达式删除任何不是:

  • \p{L} :任何语言的一封信
  • \p{N} :一个数字
  • \p{Z} :任何类型的空格或不可见的分隔符
  • \p{Sm}\p{Sc}\p{Sk} :数学,货币或通用标记为单个字符
  • \p{Mc}* :一个角色,旨在与占据额外空间的另一个角色结合(许多东方语言中的元音符号)。
  • \p{Pi}\p{Pf}\p{Pc}* :打开报价,结束报价,单词连接符(即下划线)

* :我认为这些团体也有资格被移除以用于CoreNPL。

这样,您只需要一个正则表达式filter,您可以处理字符组(具有相同的目的)而不是单个案例。

就像你有一个String一样

String xml =“….”; xml = xml.replaceAll(“[^ \ u0009 \ u000a \ u000d \ u0020- \ uD7FF \ uE000- \ uFFFD]”,“”);

这将解决您的问题