繁体   English   中英

如何从字符串中删除非 ASCII 字符?

[英]How can non-ASCII characters be removed from a string?

我有字符串"A função""Ãugent" ,其中我需要用空字符串替换çãÃ等字符。

如何从我的字符串中删除那些非 ASCII 字符?

我尝试使用以下 function 来实现它,但它无法正常工作。 一个问题是不需要的字符被空格字符取代。

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;
}

这将搜索并替换所有非ASCII字母:

String resultString = subjectString.replaceAll("[^\\x00-\\x7F]", "");

FailedDev 的回答很好,但可以改进。 如果要保留 ascii 等效项,则需要先规范化:

String subjectString = "öäü";
subjectString = Normalizer.normalize(subjectString, Normalizer.Form.NFD);
String resultString = subjectString.replaceAll("[^\\x00-\\x7F]", "");

=> will produce "oau"

这样,像“öäü”这样的字符将被映射到“oau”,这至少保留了一些信息。 如果没有规范化,生成的字符串将为空白。

这将是 Unicode 解决方案

String s = "A função, Ãugent";
String r = s.replaceAll("\\P{InBasic_Latin}", "");

\\p{InBasic_Latin}是包含以Unicode范围U + 0000..U + 007F的所有字母(见的Unicode块regular-expression.info

\\P{InBasic_Latin}是否定的\\p{InBasic_Latin}

你可以尝试这样的事情。 字母的特殊字符范围从 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());

或者您可以使用下面的函数从字符串中删除非 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();
}

一个易于阅读、可打印的 ascii 流解决方案:

String result = str.chars()
    .filter(c -> isAsciiPrintable((char) c))
    .mapToObj(c -> String.valueOf((char) c))
    .collect(Collectors.joining());

private static boolean isAsciiPrintable(char ch) {
    return ch >= 32 && ch < 127;
}

转换为“_” .map(c -> isAsciiPrintable((char) c)? c: '_')

32 到 127 相当于正则表达式[^\\x20-\\x7E] (来自对正则表达式解决方案的评论)

isAsciiPrintable 的来源: http://www.java2s.com/Code/Java/Data-Type/ChecksifthestringcontainsonlyASCIIprintablecharacters.htm

[更新解决方案]

可以与“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("\\p{InCombiningDiacriticalMarks}+")
                      .matcher(normalize)
                      .replaceAll("");
    } ...

如果您使用的是Google Guava库,则可以使用CharMatcher.retainFrom

String s = "A função";
String stripped = CharMatcher.ascii().retainFrom(s);
System.out.println(stripped); // Prints "A funo"

ASCII表包含128个代码,共有95个可打印字符,其中只有52个字符是字母:

  • [0-127] ASCII 码
    • [32-126]可打印字符
      • [48-57]位数[0-9]
      • [65-90]大写字母[AZ]
      • [97-122]小写字母[az]

您可以使用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

另请参阅:如何在密码验证中不使用特殊字符(无正则表达式)?

String s = "A função";
String stripped = s.replaceAll("\\P{ASCII}", "");
System.out.println(stripped); // Prints "A funo"

或者

private static final Pattern NON_ASCII_PATTERN = Pattern.compile("\\P{ASCII}");

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)用给定的替换字符串替换给定正则表达式(regex) 的所有实例。

用给定的替换替换此字符串中与给定正则表达式匹配的每个子字符串。

Java 具有匹配任何 ASCII 字符的"\\p{ASCII}"正则表达式构造,以及匹配任何非 ASCII 字符的反向"\\P{ASCII}" "\\p{ASCII}"正则表达式构造。 然后可以用空字符串替换匹配的字符,有效地将它们从结果字符串中删除。

String s = "A função";
String stripped = s.replaceAll("\\P{ASCII}", "");
System.out.println(stripped); // Prints "A funo"

有效正则表达式构造的完整列表记录在Pattern类中。

注意:如果您要在一次运行中多次调用此模式,则直接使用已编译的Pattern会更有效率,而不是String.replaceAll 这样模式只编译一次并重用,而不是每次调用replaceAll

public class AsciiStripper {
    private static final Pattern NON_ASCII_PATTERN = Pattern.compile("\\P{ASCII}");
    
    public static String stripNonAscii(String s) {
        return NON_ASCII_PATTERN.matcher(s).replaceAll("");
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM