Java 从字符串中删除特定unicode范围的字符
我有一个程序,可以从twitter流api实时解析推文。在存储它们之前,我将它们编码为utf8。某些字符最终在字符串中显示为?、?或???而不是它们各自的unicode代码,并导致问题。经过进一步调查,我发现问题字符来自,U+1F600-U+1F64F和“Miscellaneous,U+1F300-U+1F5FF”。我尝试删除,但没有成功,因为匹配器最终替换了字符串中的几乎所有字符,而不仅仅是我想要的unicode范围Java 从字符串中删除特定unicode范围的字符,java,regex,utf-8,Java,Regex,Utf 8,我有一个程序,可以从twitter流api实时解析推文。在存储它们之前,我将它们编码为utf8。某些字符最终在字符串中显示为?、?或???而不是它们各自的unicode代码,并导致问题。经过进一步调查,我发现问题字符来自,U+1F600-U+1F64F和“Miscellaneous,U+1F300-U+1F5FF”。我尝试删除,但没有成功,因为匹配器最终替换了字符串中的几乎所有字符,而不仅仅是我想要的unicode范围 String utf8tweet = ""; try {
String utf8tweet = "";
try {
byte[] utf8Bytes = status.getText().getBytes("UTF-8");
utf8tweet = new String(utf8Bytes, "UTF-8");
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Pattern unicodeOutliers = Pattern.compile("[\\u1f300-\\u1f64f]", Pattern.UNICODE_CASE | Pattern.CANON_EQ | Pattern.CASE_INSENSITIVE);
Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8tweet);
utf8tweet = unicodeOutlierMatcher.replaceAll(" ");
如何删除这些字符?在正则表达式模式中添加否定运算符
^
。要过滤可打印字符,可以使用以下表达式[^\\x00-\\x7F]
,应该会得到所需的结果
import java.io.UnsupportedEncodingException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class UTF8 {
public static void main(String[] args) {
String utf8tweet = "";
try {
byte[] utf8Bytes = "#Hello twitter How are you?".getBytes("UTF-8");
utf8tweet = new String(utf8Bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Pattern unicodeOutliers = Pattern.compile("[^\\x00-\\x7F]",
Pattern.UNICODE_CASE | Pattern.CANON_EQ
| Pattern.CASE_INSENSITIVE);
Matcher unicodeOutlierMatcher = unicodeOutliers.matcher(utf8tweet);
System.out.println("Before: " + utf8tweet);
utf8tweet = unicodeOutlierMatcher.replaceAll(" ");
System.out.println("After: " + utf8tweet);
}
}
结果如下:
Before: #Hello twitter How are you?
After: #Hello twitter How are you?
编辑 为了进一步解释,您还可以继续使用
\u
表单以以下方式表达范围[^\\u0000-\\u007F]
,这将匹配所有不是前128个UNICODE字符的字符(与以前相同)。如果要扩展范围以支持额外字符,可以使用UNICODE字符列表进行扩展
例如,如果要包含带重音的元音(西班牙语中使用),则应将范围扩展到\u00FF
,因此有[^\\u0000-\\u00FF]
或[^\\x00-\\xFF]
:
Before: #Hello twitter How are you? á é í ó ú
After: #Hello twitter How are you? á é í ó ú
假设
status.getText()
返回java.lang.String
byte[] utf8Bytes = status.getText().getBytes("UTF-8");
utf8tweet = new String(utf8Bytes, "UTF-8");
上述转码操作产生与以下相同的结果:
utf8tweet = status.getText();
Java字符串隐式地使用UTF-16。UTF-16和UTF-8共享相同的字符集(Unicode),因此从一个字符集转换到另一个字符集并返回原始数据
Java正则表达式支持使用的补充范围。您可以按照的答案中所述匹配它们
正如他在评论中所指出的,您很可能存在字体问题。能否显示图形通常取决于用户系统上可用的字体、所选字体以及渲染技术支持的字体替换形式。首先,相关的unicode块是用java指定的(严格遵循标准)在正则表达式中:
s = s.replaceAll("\\p{So}+", "");
我试过了。unicode的范围是
当你说它不起作用时,你到底看到了什么行为?而不是使用范围[\\u1f300-\\u1f64f],您是否尝试使用单个字符并查看其是否有效?我怀疑正则表达式范围语法在unicode字符方面会有问题。如果您看到,在GUI组件或IDE控制台输出中显示unicode编码字符串时,请不要担心,这不是由于unicode编码,而是由于选择错误不支持Unicode代码点的显示字体,如拉丁-1字体(仅255个代码点)。请尝试使用任何Unicode支持的字体,如Arial Unicode MSSorry,以防不特定!通过“不工作”“我的意思是匹配器找不到该角色,或者至少没有对其应用replaceAll函数。谢谢你,艾伊!这是一个很好的观点。但是,我注意到我的输出(即“u20A2”)中有Unicode,而有问题的字符仍然是??有问题的字符被删除了!:)(?表示本例中的一个有问题的字符)但所有字符也是如此。。。包括#<代码>之前:#MentionSomeoneYouDontWannaLose@OG_RiiSky ! 否则我会。之后:MentionSomeoneYouDontWannaLose@OG_RiiSky或者我会问题字符是否因为正则表达式认为它实际上是一个问号而被删除,或者它是否真的能够将其从该范围中拉出来?你是对的。我修改了使用过的正则表达式,修改后的答案将只匹配可打印字符。谢谢!这样做效果好多了:)出于好奇,你是如何从unicode字符范围中获得这种新模式的?在:RT@JulianSerrano01:#ContraseñasQueTuve“notelavoyadecir”le puse esa Contraseña la unica PC de la casa en ese momento,se las decia之前,它似乎正在消除范围之外的某些字符。。。之后:RT@JulianSerrano01:#Contrase asQueTuve“notelavoyadecir”le puse esa Contrase a la unica PC de la casa en ese momento,se las decia…我是从我刚才回答的另一个SO问题中得到的:)(见评论末尾的链接)。起初我没有想到,但后来它似乎是一个合适的解决方案。建议的正则表达式查找不可打印的字符,即不在指定范围内的字符。谢谢你的编辑!!我已经更改了模式中的unicode范围,以指定我希望允许的所有字符。它工作得很好:)对于任何好奇的人来说,我最终使用的模式是
[^\\u0000-\\uFFEF]
,它允许在特价和表情符号之前使用几乎所有的字符,这会破坏我的程序。我知道字体可能不会呈现字符,但是问题是,我正在通过socket.io将这些字符串发送到node.js服务器。当节点在服务器上遇到该字符时,它将其读取为传输端(未定义)
,并断开我的连接。因此,必须以某种方式删除字符:)@Saiato-听起来像是传输协议有问题。您可以在正确的Java(声明为其他符号)中使用s.replaceAll(\\p{So}+,“”)
。如何找出“So”对应于杂项?我现在使用的是块的详细形式:[\\p{inMiscellaneoussymbolsandPicturographs}\\p{inMoticons}+
@bcoughlan是的,这就是我最初使用长名称的原因,可以在javadoc中找到。虽然肯定太长了,但这至少是自文档化的。@bcoughlan在java模式javadoc中找到。请参阅类别。@b库伦好的,可以在javadoc中找到“So”:这个正则表达式不起作用您有另一个解决方案吗
class EmojiEraser{
private static final String EMOJI_RANGE_REGEX =
"[\uD83C\uDF00-\uD83D\uDDFF]|[\uD83D\uDE00-\uD83D\uDE4F]|[\uD83D\uDE80-\uD83D\uDEFF]|[\u2600-\u26FF]|[\u2700-\u27BF]";
private static final Pattern PATTERN = Pattern.compile(EMOJI_RANGE_REGEX);
/**
* Finds and removes emojies from @param input
*
* @param input the input string potentially containing emojis (comes as unicode stringfied)
* @return input string with emojis replaced
*/
public String eraseEmojis(String input) {
if (Strings.isNullOrEmpty(input)) {
return input;
}
Matcher matcher = PATTERN.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "");
}
matcher.appendTail(sb);
return sb.toString();
}
}