如何在java中从字符串中删除无效的unicode字符
我正在使用解析一些社交媒体内容。不幸的是,根据,该文件包含的字符不是有效的unicode字符或unicode替换字符。例如,它们是或。如果这些字符在文件中,coreNLP会响应如下错误消息:如何在java中从字符串中删除无效的unicode字符,java,regex,parsing,unicode,stanford-nlp,Java,Regex,Parsing,Unicode,Stanford Nlp,我正在使用解析一些社交媒体内容。不幸的是,根据,该文件包含的字符不是有效的unicode字符或unicode替换字符。例如,它们是或。如果这些字符在文件中,coreNLP会响应如下错误消息: Nov 15, 2015 5:15:38 PM edu.stanford.nlp.process.PTBLexer next WARNING: Untokenizable: ? (U+D83D, decimal: 55357) 根据答案,我尝试了document.replaceAll(“\\p{C},”)
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只是忽略它无法处理的字符,所以这不是问题。就像您有一个字符串一样 字符串xml=“…”; xml=xml.replaceAll(“[^\u0009\u000a\u000d\u0020-\uD7FF\uE000-\uFFFD],”)
这将解决您的问题使用以下方法删除特定的不需要的字符:
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而被删除
这样,您只需要一个正则表达式过滤器,就可以处理字符组(具有相同的目的),而不是单个案例。在某种程度上,和提供的两个答案都有帮助,但并不完全正确
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<HasWord> sentence : tokenizer) {
List<TaggedWord> tagged = tagger.tagSentence(sentence);
GrammaticalStructure gs = parser.predict(tagged);
System.err.println(gs);
}
您可以使用其他选项替换第4行中的noneDelete
。我引用曼宁的话:
(…)由六个选项组成的完整集合,包括是否记录“无”、“第一个”或“全部”的警告,以及是否删除它们或将它们作为单字符标记包含在输出中:noneDelete、firstDelete、allDelete、noneKeep、firstKeep、allKeep
这意味着,要在不获取所有错误消息的情况下保留字符,最好的方法是使用选项
noneKeep
。这种方法比任何删除这些字符的尝试都要优雅得多。我们在其他地方看到了替换所有字符的负面影响。因此,我建议替换字符,如果它是非BPM字符,如下所示
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();
}
replaceAll
方法创建一个新的字符串
;它不修改文档
。您是否执行了document=document.replaceAll(…)
(或其他捕获返回值的操作)?我在这行中的DocumentProcessor
类的实例化中使用了它:DocumentPreprocessor标记器=新的DocumentPreprocessor(新的StringReader(document.replaceAll(\\p{C},“”))代码>。它说字符串文字没有被双引号正确地关闭。\u
所有的\u
都需要双转义->\\u
嗯,好的,这就成功了。U+D83D
错误似乎消失了,可能还有其他错误(我有大量语料库,所以我不确定)。我仍然得到的是U+FFFD
,U+FE0F
,U+203C
和U+3010
。至少我看不出还有其他急事。我怎样才能摆脱这些?另一件事,你能具体说明被删除的是什么吗?我希望确保没有任何我不想删除的内容被删除。做得好,我已经更新了我的答案,使用一种“不在允许的unicode组中”的方法来优化流程。尝试一下并阅读相关文档。等待官方的回应,我认为这可能是最好的方法。谢谢你的更新。不过,我觉得这可能太过分了。例如,一个问题是U+3010
(),它属于Ps
(任何类型的开口支架)组。但是(,[或{也会被删除,在我的情况下是不必要的吗?在我开始删除我不想删除的东西之前,我宁愿接受错误消息,让CoreNLP自己完成工作。使用过滤器测试CoreNPL提供的输出是否有差异(可能是这样,可能不是这样)。作为一个白名单,您只需简单地将您想要保存的字符添加到列表中即可。“[^\\p{L}.\\\\\\(\\)\[\\\]\{\\})]”
。是的,您是对的。这可能是解决我问题的最佳方法。谢谢!
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();
}