Я бы сделал что-то вроде этого:
/**
*
* HTML 4 Specification ID and NAME tokens must begin with a letter
* ([A-Za-z]) and may be followed by any number of letters, digits ([0-9]),
* hyphens ("-"), underscores ("_"), colons (":"), and periods (".").
*
* @param s
* @return
*/
public static String sanitizeHTMLIdAttribute(String s) {
if (s == null) return null;
StringBuilder sb = new StringBuilder();
int firstLegal = 0;
while (firstLegal < s.length() && !isAZ(s.charAt(firstLegal)))
++firstLegal;
for (int i = firstLegal; i < s.length(); ++i){
final char ch = s.charAt(i);
if (isOkIdInnerChar(ch)) sb.append(ch);
}
return sb.length() == s.length()? s : sb.toString();
}
private static boolean isOkIdInnerChar(char ch) {
return isAZ(ch) || isNum(ch) || isSpecial(ch);
}
private static boolean isSpecial(char ch) {
switch (ch) {
case '-': case '_':
case ':': case '.':
return true;
default:
return false;
}
}
private static boolean isAZ(char ch) {
return ('A' <= ch && ch <= 'Z') || ('a' <= ch && ch <= 'z');
}
private static boolean isNum(char ch) {
return '0' <= ch && ch <= '9';
}
... за исключением того, что я, вероятно, предпочел бы бросить NullPointerException
, если s == null
, и IllegalArgumentException
, если s
не содержит допустимых символов, но это вопрос предпочтения, конечно. Некоторые дополнительные функции:
- Если
s
является действительным идентификатором, он возвращается как есть, чтобы сэкономить пространство (меньше плавающих экземпляров строк) и время (String
конструкция дорогая - да, я знаю, что выделение дешево, но больше там, чем распределение).
- Я не использую
Character.isDigit
, потому что он возвращает true для всех цифр Unicode, включая такие вещи, как "٣"
- Я не использую
Character.isLetter
, потому что он возвращает true для всех букв Unicode, включая такие вещи, как "å"