【问题标题】:Function to Sanitize HTML Id attribute in Java在 Java 中清理 HTML Id 属性的函数
【发布时间】:2009-09-10 22:45:40
【问题描述】:

我已经编写了下一个函数。但肯定有人有更优雅的方式来执行这项任务。

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

【问题讨论】:

    标签: java html sanitization sanitize


    【解决方案1】:

    我会这样做:

    /**
     * 
     * 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';
    }
    

    ...除了如果s == nullIllegalArgumentException 如果s 不包含合法字符,我可能更愿意抛出NullPointerException,但这是一个偏好问题,当然。一些额外的功能:

    • 如果 s 是一个有效的 ID,它会按原样返回以节省空间(更少的字符串实例浮动)和时间(String 构造很昂贵——是的,我知道分配很便宜,但还有更多就在那里比分配)。
    • 我不使用Character.isDigit,因为它对所有 Unicode 数字返回true,包括像“٣”这样的东西
    • 我不使用Character.isLetter,因为它对所有 Unicode 字母返回true,包括像“å”这样的东西

    【讨论】:

      【解决方案2】:

      使用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)) {
      
        }
      }
      

      【讨论】:

      • 仅供参考:字符 e-acute '\u00e9' 是字母或数字,但不是有效的 HTML 标识符。该方法将为各种 Unicode 字符返回 true。
      【解决方案3】:

      您可能想要检查表达式(正则表达式不是我的强项),但这应该会删除无效字符:

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

      【讨论】:

        猜你喜欢
        • 2016-10-02
        • 2019-12-15
        • 2011-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-20
        • 2013-01-24
        • 1970-01-01
        相关资源
        最近更新 更多