2013-01-31 27 views
18

Tôi đã các ký tự sau đó tôi muốn được coi là "bất hợp pháp":Java chức năng trả về nếu chuỗi chứa ký tự bất hợp pháp

~, #, @, *, +, %, {, }, <, >, [, ], |, , , \, _, ^

Tôi muốn viết một phương pháp mà kiểm tra một chuỗi và xác định (true/false) nếu chuỗi chứa những bất hợp pháp:

public boolean containsIllegals(String toExamine) { 
    return toExamine.matches("^.*[~#@*+%{}<>[]|\"\\_^].*$"); 
} 

Tuy nhiên, một matches(...) kiểm tra đơn giản là không khả thi cho việc này. Tôi cần phương pháp để quét mọi ký tự trong chuỗi và đảm bảo rằng nó không phải là một trong các ký tự này. Tất nhiên, tôi có thể làm điều gì đó khủng khiếp như:

public boolean containsIllegals(String toExamine) { 
    for(int i = 0; i < toExamine.length(); i++) { 
     char c = toExamine.charAt(i); 

     if(c == '~') 
      return true; 
     else if(c == '#') 
      return true; 

     // etc... 
    } 
} 

Có/cách hiệu quả thêm thanh lịch thực hiện điều này?

+5

tại sao không thể sử dụng 'kết quả khớp'? –

+0

vì đó không phải là mát mẻ! – thang

Trả lời

25

Bạn có thể tận dụng PatternMatcher lớp ở đây. Bạn có thể đặt tất cả các ký tự được lọc trong một lớp nhân vật và sử dụng phương thức Matcher#find() để kiểm tra xem mẫu của bạn có sẵn trong chuỗi hay không.

Bạn có thể làm điều đó như thế này: -

public boolean containsIllegals(String toExamine) { 
    Pattern pattern = Pattern.compile("[~#@*+%{}<>\\[\\]|\"\\_^]"); 
    Matcher matcher = pattern.matcher(toExamine); 
    return matcher.find(); 
} 

find() phương pháp sẽ trở thành sự thật, nếu mô hình cụ thể được tìm thấy trong chuỗi, dù chỉ một lần.


Một cách khác chưa được chỉ ra là sử dụng String#split(regex). Chúng ta có thể chia chuỗi trên mẫu đã cho và kiểm tra độ dài của mảng. Nếu chiều dài là 1 thì mẫu không nằm trong chuỗi.

public boolean containsIllegals(String toExamine) { 
    String[] arr = toExamine.split("[~#@*+%{}<>\\[\\]|\"\\_^]", 2); 
    return arr.length > 1; 
} 

Nếu arr.length > 1, có nghĩa là chuỗi chứa một trong những nhân vật trong các mô hình, đó là lý do tại sao nó được tách ra. Tôi đã vượt qua limit = 2 làm tham số thứ hai cho split, bởi vì chúng tôi chỉ chấp nhận một lần.

+0

Sạch sẽ và giải thích tốt nhất. – IAmYourFaja

+0

Đối với những người theo dõi và cũng nhận được thông tin chi tiết, hãy chú ý rằng với "matcher.find" bạn sử dụng cụm từ thông dụng ngắn hơn chỉ với nội dung bên trong dấu ngoặc vuông, nhưng với "matcher.matches", bạn sẽ sử dụng biểu thức dài hơn. Cả hai kỹ thuật đã vượt qua các bài kiểm tra đơn vị của tôi miễn là cụm từ thông dụng chính xác được sử dụng cho mỗi bài kiểm tra. – Ted

+0

Phương pháp thứ hai rất tuyệt! Tốt đẹp –

10

tôi cần phương pháp để quét tất cả các nhân vật trong chuỗi

Nếu bạn phải làm điều đó nhân vật-by-nhân vật, regexp có lẽ không phải là một cách tốt để đi. Tuy nhiên, vì tất cả các nhân vật vào "danh sách đen" của bạn có mã ít hơn 128, bạn có thể làm điều đó với một boolean mảng nhỏ:

static final boolean blacklist[] = new boolean[128]; 

static { 
    // Unassigned elements of the array are set to false 
    blacklist[(int)'~'] = true; 
    blacklist[(int)'#'] = true; 
    blacklist[(int)'@'] = true; 
    blacklist[(int)'*'] = true; 
    blacklist[(int)'+'] = true; 
    ... 
} 

static isBad(char ch) { 
    return (ch < 128) && blacklist[(int)ch]; 
} 
+0

Nếu tôi không nhầm, boolean uninitialised trở thành sai trong Java, phải không? – 11684

+0

@ 11684 Đúng - các phần tử của mảng 'boolean' ban đầu là' false'. – dasblinkenlight

+1

Có lẽ đó có thể là một phần của câu trả lời, vì vậy các lập trình viên bắt đầu cũng có thể hiểu được nó? – 11684

7

Nếu bạn không thể sử dụng trình ghép nối, thì bạn có thể làm một cái gì đó như thế này, sạch hơn một loạt các câu lệnh if hoặc mảng byte khác nhau.

for(int i = 0; i < toExamine.length(); i++) { 
    char c = toExamine.charAt(i); 
    if("~#@*+%{}<>[]|\"_^".contains(c)){ 
     return true; 
    } 
} 
5

Thử phủ định của một lớp nhân vật bao gồm tất cả các nhân vật danh sách đen:

public boolean containsIllegals(String toExamine) { 
    return toExamine.matches("[^~#@*+%{}<>\\[\\]|\"\\_^]*"); 
} 

này sẽ trở lại true nếu chuỗi chứa bất hợp pháp (chức năng ban đầu của bạn dường như trở false trong trường hợp đó).

Dấu mũ ^ chỉ ở bên phải của khung mở [ phủ nhận lớp ký tự. Lưu ý rằng trong String.matches() bạn không cần neo ^$ vì nó tự động khớp với toàn bộ chuỗi.

2

Một cách khá nhỏ gọn để làm điều này sẽ phải dựa vào phương pháp String.replaceAll:

public boolean containsIllegal(final String toExamine) { 
    return toExamine.length() != toExamine.replaceAll(
      "[~#@*+%{}<>\\[\\]|\"\\_^]", "").length(); 
} 
6

Sử dụng một liên tục cho tránh được biên dịch lại các regex trong mỗi xác nhận.

private static final Pattern INVALID_CHARS_PATTERN = 
           Pattern.compile("^.*[~#@*+%{}<>\\[\\]|\"\\_].*$"); 

Và thay đổi mã của bạn để:

public boolean containsIllegals(String toExamine) { 
    return INVALID_CHARS_PATTERN.matcher(toExamine).matches(); 
} 

Đây là cách hiệu quả nhất với Regex.

Các vấn đề liên quan