Функция для очистки атрибута HTML Id в Java - PullRequest
1 голос
/ 10 сентября 2009

Я кодировал следующую функцию. Но наверняка у кого-то есть более элегантный способ выполнить эту задачу.

/**
 * 
 * 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) {
  String sanitize = "";
  if(s!=null) {
    for(int i = 0; i < s.length(); i++) {
      if(s.charAt(i) == '-' || s.charAt(i) == '_' || s.charAt(i) == ':' || 
         s.charAt(i) == '.' || s.charAt(i) == '0' || s.charAt(i) == '1' || 
         s.charAt(i) == '2' || s.charAt(i) == '3' || s.charAt(i) == '4' || 
         s.charAt(i) == '5' || s.charAt(i) == '6' || s.charAt(i) == '7' || 
         s.charAt(i) == '8' || s.charAt(i) == '9' || 
         s.charAt(i) == 'a' || s.charAt(i) == 'b' || s.charAt(i) == 'c' || 
         s.charAt(i) == 'd' || s.charAt(i) == 'e' || s.charAt(i) == 'f' || 
         s.charAt(i) == 'g' || s.charAt(i) == 'h' || s.charAt(i) == 'i' || 
         s.charAt(i) == 'j' || s.charAt(i) == 'k' || s.charAt(i) == 'l' ||  
         s.charAt(i) == 'm' || s.charAt(i) == 'n' || s.charAt(i) == 'o' ||
         s.charAt(i) == 'p' || s.charAt(i) == 'q' || s.charAt(i) == 'r' || 
         s.charAt(i) == 's' || s.charAt(i) == 't' || s.charAt(i) == 'u' || 
         s.charAt(i) == 'w' || s.charAt(i) == 'x' || s.charAt(i) == 'y' ||
     s.charAt(i) == 'z' || 
         s.charAt(i) == 'A' || s.charAt(i) == 'B' || s.charAt(i) == 'C' || 
         s.charAt(i) == 'D' || s.charAt(i) == 'E' || s.charAt(i) == 'F' || 
         s.charAt(i) == 'G' || s.charAt(i) == 'H' || s.charAt(i) == 'I' ||
         s.charAt(i) == 'J' || s.charAt(i) == 'K' || s.charAt(i) == 'L' ||
         s.charAt(i) == 'M' || s.charAt(i) == 'N' || s.charAt(i) == 'O' ||
         s.charAt(i) == 'P' || s.charAt(i) == 'Q' || s.charAt(i) == 'R' || 
         s.charAt(i) == 'S' || s.charAt(i) == 'T' || s.charAt(i) == 'U' || 
         s.charAt(i) == 'W' ||  s.charAt(i) == 'X' || s.charAt(i) == 'Y' || 
         s.charAt(i) == 'Z') {
              sanitize += s.charAt(i);
      }
    }
    if(sanitize.length()>0) {
      while(sanitize.charAt(0) == '0' || sanitize.charAt(0) == '1' || 
            sanitize.charAt(0) == '2' || sanitize.charAt(0) == '3' || 
            sanitize.charAt(0) == '4' || sanitize.charAt(0) == '5' || 
            sanitize.charAt(0) == '6' || sanitize.charAt(0) == '7' || 
            sanitize.charAt(0) == '8' || sanitize.charAt(0) == '9') {
                sanitize = sanitize.substring(1, sanitize.length()); 
      }
    }
    return sanitize;
  } 
  return null;      
}

Ответы [ 3 ]

1 голос
/ 10 сентября 2009

Я бы сделал что-то вроде этого:

/**
 * 
 * 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, включая такие вещи, как "å"
0 голосов
/ 10 сентября 2009

Возможно, вы захотите проверить выражения (регулярное выражение не моя сильная сторона), но это должно сбрасывать недопустимые символы:

  private static Pattern INVALID_LEADING = Pattern.compile("^[^a-zA-Z]+");
  private static Pattern INVALID = Pattern
      .compile("[^\\w\\u002e\\u003a\\u002d\\u005f]+");

  private static String sanitize(String id) {
    Matcher matcher = INVALID_LEADING.matcher(id);
    if (matcher.find()) {
      id = matcher.replaceFirst("");
    }
    Matcher invalid = INVALID.matcher(id);
    if (invalid.find()) {
      id = invalid.replaceAll("");
    }
    return id;
  }

Если вы не довольны регулярным выражением, помните, что многие из ваших персонажей находятся в смежных диапазонах, поэтому их можно обнаружить с помощью таких методов:

  private static boolean isLatinDigit(char ch) {
    return ch >= '0' && ch <= '9';
  }
0 голосов
/ 10 сентября 2009

Вы можете значительно сократить свой код, используя Character.isLetterOrDigit(char); например,

for(int i = 0; i < s.length(); i++) {
  char c = s.charAt(i);

  if (Character.isLetterOrDigit(c) || c == '.' || etc ...) {

  }
}

Вы можете сделать это вместе с сохранением разрешенных знаков препинания в Set; например,

private static final Set<Character> ALLOWED =
  new HashSet<Character>(Arrays.asList('.', '-', '_', ':'));

for(int i = 0; i < s.length(); i++) {
  char c = s.charAt(i);

  if (ALLOWED.contains(c)) {

  }
}
...