如何从字符串中删除非 ASCII 字符?
Posted
技术标签:
【中文标题】如何从字符串中删除非 ASCII 字符?【英文标题】:How can non-ASCII characters be removed from a string? 【发布时间】:2012-01-21 02:58:40 【问题描述】:我有字符串"A função"
、"Ãugent"
,其中我需要用空字符串替换ç
、ã
和Ã
等字符。
如何从字符串中删除那些非 ASCII 字符?
我尝试使用以下函数来实现它,但它无法正常工作。一个问题是不需要的字符被空格字符替换。
public static String matchAndReplaceNonEnglishChar(String tmpsrcdta)
String newsrcdta = null;
char array[] = Arrays.stringToCharArray(tmpsrcdta);
if (array == null)
return newsrcdta;
for (int i = 0; i < array.length; i++)
int nVal = (int) array[i];
boolean bISO =
// Is character ISO control
Character.isISOControl(array[i]);
boolean bIgnorable =
// Is Ignorable identifier
Character.isIdentifierIgnorable(array[i]);
// Remove tab and other unwanted characters..
if (nVal == 9 || bISO || bIgnorable)
array[i] = ' ';
else if (nVal > 255)
array[i] = ' ';
newsrcdta = Arrays.charArrayToString(array);
return newsrcdta;
【问题讨论】:
Fastest way to strip all non-printable characters from a Java String的可能重复 【参考方案1】:这将搜索并替换所有非 ASCII 字母:
String resultString = subjectString.replaceAll("[^\\x00-\\x7F]", "");
【讨论】:
感谢您的回复.. 但是这个“A”仍然无法用空字符串替换。 @rahulsri A 是一个完全有效的 ASCII 字符。为什么要换? @Dev 我认为它不可见,但这是一个拉丁字符,其 Unicode 值为“\u00c3”。 您很可能也想去除不可打印和控制字符。在这种情况下,您将使用以下正则表达式:"[^\\x20-\\x7E]"
或者简单地说:"[^ -~]"
"[^\\pASCII]"
是 "[^\\x00-\\x7F]"
的等效替代品。【参考方案2】:
这将是 Unicode 解决方案
String s = "A função, Ãugent";
String r = s.replaceAll("\\PInBasic_Latin", "");
\pInBasic_Latin
是包含 Unicode 范围 U+0000..U+007F 中所有字母的 Unicode 块(请参阅regular-expression.info)
\PInBasic_Latin
是否定的\pInBasic_Latin
【讨论】:
(对像我一样困惑的人请注意:大写的 \P 是否定的。) @user1187719,您可能比“这不起作用”更准确。这个答案已经得到了一些支持,所以它不能完全没用。当然,如果你有Java 7 之前的 Java 版本,我同意。正则表达式中的 Unicode 在那里不起作用。 @stema - 我在 Java 6 中运行它,所以你的 Java 7 理论站得住脚。 它会删除特殊字符并且“不”用 ASCII 等效字符替换它们 @Ali,是的,您完全理解我的回答。这是5年前的要求。如果这不是您所需要的,请使用 Michael Böcklings 的答案。【参考方案3】:你可以试试这样的。字母的特殊字符范围从 192 开始,因此您可以在结果中避免此类字符。
String name = "A função";
StringBuilder result = new StringBuilder();
for(char val : name.toCharArray())
if(val < 192) result.append(val);
System.out.println("Result "+result.toString());
【讨论】:
为什么要检查 192 而不是 128(ASCII 表是什么)?您假设某种编码(我认为是 ISO-8859-1),但是如果编码是 ISO-8859-2/3/4/5/7... 怎么办?表格的那些区域有字母。 是的,这取决于我们要允许的字符数以及编码。这只是一个例子。我们可以根据需要的字符和编码添加条件。【参考方案4】:FailedDev 的回答很好,但可以改进。如果要保留 ascii 等效项,则需要先进行规范化:
String subjectString = "öäü";
subjectString = Normalizer.normalize(subjectString, Normalizer.Form.NFD);
String resultString = subjectString.replaceAll("[^\\x00-\\x7F]", "");
=> will produce "oau"
这样,像“öäü”这样的字符将被映射到“oau”,这至少保留了一些信息。如果没有规范化,结果字符串将为空白。
【讨论】:
您的回答很好,但可以改进。在代码中删除正则表达式的使用并用 for 循环替换它的速度非常快(20-40 倍)。更多信息:***.com/a/15191508/2511884 感谢您的提示。性能差异的程度出乎意料。 您可能想使用 Normalizer.Form.NFKD 而不是 NFD - NFKD 会将连字之类的内容转换为 ascii 字符(例如 fi 到 fi),NFD 不会这样做。Normalizer.normalize("ãéío – o áá", Normalizer.Form.NFD).replaceAll("[^\\x00-\\x7F]", "");
产生“aeio o aa”,但echo "ãéío – o áá" | iconv -f utf8 -t ascii//TRANSLIT
产生“aeio - o aa”。有没有办法让java像iconv一样用“-”替换“-”?【参考方案5】:
或者您可以使用下面的函数从字符串中删除非 ascii 字符。 您将了解内部工作。
private static String removeNonASCIIChar(String str)
StringBuffer buff = new StringBuffer();
char chars[] = str.toCharArray();
for (int i = 0; i < chars.length; i++)
if (0 < chars[i] && chars[i] < 127)
buff.append(chars[i]);
return buff.toString();
【讨论】:
【参考方案6】:[更新的解决方案]
可与“Normalize”(规范分解)和“replaceAll”一起使用,以将其替换为适当的字符。
import java.text.Normalizer;
import java.text.Normalizer.Form;
import java.util.regex.Pattern;
public final class NormalizeUtils
public static String normalizeASCII(final String string)
final String normalize = Normalizer.normalize(string, Form.NFD);
return Pattern.compile("\\pInCombiningDiacriticalMarks+")
.matcher(normalize)
.replaceAll("");
...
【讨论】:
【参考方案7】:如果您使用的是Google Guava 库,则可以使用CharMatcher.retainFrom
:
String s = "A função";
String stripped = CharMatcher.ascii().retainFrom(s);
System.out.println(stripped); // Prints "A funo"
【讨论】:
【参考方案8】:ASCII表包含128个代码,共有95个printable characters,其中只有52个字符是字母:
[0-127]
ASCII 码
[32-126]
可打印字符
[48-57]
数字 [0-9]
[65-90]
大写字母 [A-Z]
[97-122]
小写字母 [a-z]
您可以使用String.codePoints
方法获取超过此字符串字符的int
值和filter
输出非ASCII 字符的流:
String str1 = "A função, Ãugent";
String str2 = str1.codePoints()
.filter(ch -> ch < 128)
.mapToObj(Character::toString)
.collect(Collectors.joining());
System.out.println(str2); // A funo, ugent
或者您可以显式指定字符范围。例如过滤掉 一切 除了字母:
String str3 = str1.codePoints()
.filter(ch -> ch >= 'A' && ch <= 'Z'
|| ch >= 'a' && ch <= 'z')
.mapToObj(Character::toString)
.collect(Collectors.joining());
System.out.println(str3); // Afunougent
另见:How do I not take Special Characters in my Password Validation (without Regex)?
【讨论】:
【参考方案9】:String s = "A função";
String stripped = s.replaceAll("\\PASCII", "");
System.out.println(stripped); // Prints "A funo"
或
private static final Pattern NON_ASCII_PATTERN = Pattern.compile("\\PASCII");
public static String matchAndReplaceNonEnglishChar(String tmpsrcdta)
return NON_ASCII_PATTERN.matcher(s).replaceAll("");
public static void main(String[] args)
matchAndReplaceNonEnglishChar("A função"); // Prints "A funo"
说明
方法String.replaceAll(String regex, String replacement)
用给定的替换字符串替换给定regular expression(正则表达式)的所有实例。
用给定的替换替换此字符串中与给定正则表达式匹配的每个子字符串。
Java 具有匹配任何 ASCII 字符的 "\pASCII"
正则表达式构造,以及匹配任何非 ASCII 字符的反面 "\PASCII"
。然后可以将匹配的字符替换为空字符串,从而有效地将它们从结果字符串中删除。
String s = "A função";
String stripped = s.replaceAll("\\PASCII", "");
System.out.println(stripped); // Prints "A funo"
有效正则表达式构造的完整列表记录在 Pattern
类中。
注意:如果您要在一次运行中多次调用此模式,则直接使用已编译的Pattern
比使用String.replaceAll
更有效。这样,模式只编译一次并重用,而不是每次调用replaceAll
:
public class AsciiStripper
private static final Pattern NON_ASCII_PATTERN = Pattern.compile("\\PASCII");
public static String stripNonAscii(String s)
return NON_ASCII_PATTERN.matcher(s).replaceAll("");
【讨论】:
以上是关于如何从字符串中删除非 ASCII 字符?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用正则表达式和 Notepad++ 删除所有非 ASCII 字符?