ฉันจะแทนที่อักขระ Unicode ที่ไม่สามารถพิมพ์ได้ใน Java ได้อย่างไร


89

สิ่งต่อไปนี้จะแทนที่อักขระควบคุม ASCII (ชวเลขสำหรับ[\x00-\x1F\x7F]):

my_string.replaceAll("\\p{Cntrl}", "?");

ต่อไปนี้จะแทนที่อักขระที่ไม่สามารถพิมพ์ได้ของ ASCII ทั้งหมด (ชวเลขสำหรับ[\p{Graph}\x20]) รวมถึงอักขระที่เน้นเสียง:

my_string.replaceAll("[^\\p{Print}]", "?");

อย่างไรก็ตามไม่สามารถใช้ได้กับสตริง Unicode ใครมีวิธีที่ดีในการลบอักขระที่ไม่สามารถพิมพ์ได้จากสตริง Unicode?


2
เช่นเดียวกับภาคผนวก: รายการหมวดหมู่ทั่วไปของ Unicode สามารถพบได้ในUAX # 44
McDowell


1
@Stewart: สวัสดีคุณดูคำถาม / คำตอบนอกเหนือจากชื่อเรื่องแล้วหรือยัง!?
dagnelies

1
@Stewart: คำถามอื่น ๆ นั้นครอบคลุมเฉพาะส่วนย่อยของ ascii ของอักขระที่ไม่สามารถพิมพ์ได้ !!!
dagnelies

คำตอบ:


136
my_string.replaceAll("\\p{C}", "?");

ดูเพิ่มเติมเกี่ยวกับUnicode regex java.util.regexPattern/ String.replaceAllสนับสนุนพวกเขา


ใน java 1.6 อย่างน้อยไม่มีการสนับสนุนสำหรับพวกเขา download.oracle.com/javase/6/docs/api/java/util/regex/… ... ฉันลองใช้ไลน์ของคุณด้วยและนอกจากจะไม่มีแบ็กสแลชหายไปแล้วมันก็ใช้ไม่ได้
dagnelies

ใช้งานได้: char c = 0xFFFA; String.valueOf(c).replaceAll("\\p{C}", "?");ใน javadoc สำหรับรูปลักษณ์ในส่วนการสนับสนุน Unicodeกล่าวว่ารองรับหมวดหมู่
Op De Cirkel

คุณพูดถูก! ฉันขอโทษ. ฉันไม่ได้สังเกตเห็นเพราะฉันต้องเพิ่มหมวดหมู่ Zl Zp เนื่องจากส่วนใหญ่เป็นที่มาของปัญหา มันทำงานได้อย่างสมบูรณ์ คุณช่วยแก้ไขโพสต์ของคุณเล็กน้อยเพื่อให้ฉันโหวตอีกครั้งได้ไหม
dagnelies

6
นอกจากนี้ยังมีอักขระช่องว่างที่มองไม่เห็น (เช่น 0x0200B) ซึ่งเป็นส่วนหนึ่งของกลุ่ม \ p {Zs} น่าเสียดายที่อันนี้มีช่องว่างปกติด้วย สำหรับผู้ที่พยายามกรองสตริงอินพุตที่ไม่ควรมีช่องว่างสตริงs.replaceAll("[\\p{C}\\p{Z}]", "")จะสร้างเสน่ห์
Andrey L

1
นี่คือสิ่งที่ฉันกำลังมองหาฉันพยายามreplaceAll("[^\\u0000-\\uFFFF]", "")แต่ไม่ประสบความสำเร็จ
Bibaswann Bandyopadhyay

58

Op De Cirkel พูดถูกเป็นส่วนใหญ่ ข้อเสนอแนะของเขาจะใช้ได้ผลในกรณีส่วนใหญ่:

myString.replaceAll("\\p{C}", "?");

แต่ถ้าmyStringอาจมีจุดรหัสที่ไม่ใช่ BMP ก็ซับซ้อนกว่านี้ \p{C}มี codepoints \p{Cs}ตัวแทนของ วิธีการเปลี่ยนข้างต้นจะทำให้จุดรหัสที่ไม่ใช่ BMP เสียหายโดยบางครั้งแทนที่เพียงครึ่งหนึ่งของคู่ตัวแทน เป็นไปได้ว่านี่เป็นจุดบกพร่องของ Java แทนที่จะเป็นพฤติกรรมที่ตั้งใจไว้

การใช้หมวดหมู่องค์ประกอบอื่น ๆ เป็นตัวเลือก:

myString.replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "?");

อย่างไรก็ตามอักขระตัวแทนเดี่ยวที่ไม่ได้เป็นส่วนหนึ่งของคู่ (อักขระตัวแทนแต่ละตัวมีจุดรหัสที่กำหนด) จะไม่ถูกลบออก แนวทางที่ไม่ใช่ regex เป็นวิธีเดียวที่ฉันรู้ว่าจะจัดการได้อย่างเหมาะสม\p{C}:

StringBuilder newString = new StringBuilder(myString.length());
for (int offset = 0; offset < myString.length();)
{
    int codePoint = myString.codePointAt(offset);
    offset += Character.charCount(codePoint);

    // Replace invisible control characters and unused code points
    switch (Character.getType(codePoint))
    {
        case Character.CONTROL:     // \p{Cc}
        case Character.FORMAT:      // \p{Cf}
        case Character.PRIVATE_USE: // \p{Co}
        case Character.SURROGATE:   // \p{Cs}
        case Character.UNASSIGNED:  // \p{Cn}
            newString.append('?');
            break;
        default:
            newString.append(Character.toChars(codePoint));
            break;
    }
}

8

คุณอาจสนใจหมวดหมู่ Unicode "อื่น ๆ การควบคุม"และอาจเป็น "อื่น ๆ รูปแบบ" (น่าเสียดายที่หลังนี้มีทั้งอักขระที่พิมพ์ไม่ได้และพิมพ์ได้)

ในนิพจน์ทั่วไปของ Java คุณสามารถตรวจสอบได้โดยใช้\p{Cc}และ\p{Cf}ตามลำดับ


ดีนิพจน์ java ที่แย่เกินไปไม่มี แต่อย่างน้อยฉันก็ได้รายชื่อแล้ว ... ดีกว่าไม่มีอะไรเลย ขอบคุณ
dagnelies

5

วิธีการเพื่อเป้าหมายของคุณ

public static String removeNonAscii(String str)
{
    return str.replaceAll("[^\\x00-\\x7F]", "");
}

public static String removeNonPrintable(String str) // All Control Char
{
    return str.replaceAll("[\\p{C}]", "");
}

public static String removeSomeControlChar(String str) // Some Control Char
{
    return str.replaceAll("[\\p{Cntrl}\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}]", "");
}

public static String removeFullControlChar(String str)
{
    return removeNonPrintable(str).replaceAll("[\\r\\n\\t]", "");
} 

0

ฉันใช้ฟังก์ชันง่ายๆนี้สำหรับสิ่งนี้:

private static Pattern pattern = Pattern.compile("[^ -~]");
private static String cleanTheText(String text) {
    Matcher matcher = pattern.matcher(text);
    if ( matcher.find() ) {
        text = text.replace(matcher.group(0), "");
    }
    return text;
}

หวังว่านี่จะเป็นประโยชน์


0

จากคำตอบของOp De Cirkelและnoackjrสิ่งต่อไปนี้คือสิ่งที่ฉันทำเพื่อทำความสะอาดสตริงทั่วไป: 1. การตัดช่องว่างที่นำหน้าหรือต่อท้าย, 2. dos2unix, 3. mac2unix, 4. การลบ "อักขระ Unicode ที่มองไม่เห็น" ทั้งหมดยกเว้นช่องว่าง:

myString.trim.replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("[\\p{Cc}\\p{Cf}\\p{Co}\\p{Cn}&&[^\\s]]", "")

ทดสอบด้วย Scala REPL


0

ฉันขอเสนอให้ลบอักขระที่ไม่สามารถพิมพ์ได้เช่นด้านล่างแทนที่จะแทนที่

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

-4

ฉันได้ออกแบบรหัสใหม่สำหรับหมายเลขโทรศัพท์ +9 (987) 124124 แยกตัวเลขจากสตริงใน Java

 public static String stripNonDigitsV2( CharSequence input ) {
    if (input == null)
        return null;
    if ( input.length() == 0 )
        return "";

    char[] result = new char[input.length()];
    int cursor = 0;
    CharBuffer buffer = CharBuffer.wrap( input );
    int i=0;
    while ( i< buffer.length()  ) { //buffer.hasRemaining()
        char chr = buffer.get(i);
        if (chr=='u'){
            i=i+5;
            chr=buffer.get(i);
        }

        if ( chr > 39 && chr < 58 )
            result[cursor++] = chr;
        i=i+1;
    }

    return new String( result, 0, cursor );
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.