如何检查一个字符串的每个字符都在指定范围内?(比如验证用户名是否合法)

rfc 3986中规定,http url的域名部分,必须是由0-9、a-z、A-Z、"%"、"!" 、 "TMPL__XXXX_BODY_XXXXquot; 、 "&" 、 "'" 、 "(" 、 ")"、"*" 、 "+" 、 "," 、 ";" 、 "=" 这些字符组成。那么如何快速的验证一个字符串是否满足这个限定呢?

const std::string pattern = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
                              "MNOPQRSTUVWXYZ-._~%!TMPL__XXXX_BODY_XXXXamp;'()*+,;=";
  const std::string input = argv[1];
  bool isOk = true;
  for (std::string::size_type i = 0; i != input.size(); ++i) {
    char c = input[i];
    bool found = false;
    for (std::string::size_type j = 0; j != pattern.size(); ++j) {
      if (c == pattern[j]) {
        found = true;
        break;
      }
    }
    if (!found) {
      isOk = false;
      break;
    }
  }
  std::cout << input << ":" << (isOk ? "true" : "false") << std::endl;

这是最直观最简单的办法。但是有两层循环。仔细看,最里面那层循环,只是为了查找一个元素是否在一个集合中,所以完全可以用标准的set来做。为了更高效点,此处可使用bitset。

  const std::string pattern = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKL"
                              "MNOPQRSTUVWXYZ-._~%!TMPL__XXXX_BODY_XXXXamp;'()*+,;=";
  std::bitset s;
  for(char c:pattern){
      s[(unsigned char)c]=1;
  }
  const std::string input = argv[1];
  bool isOk = true;
  for (std::string::size_type i = 0; i != input.size(); ++i) {
    char c = input[i];
    if(s[(unsigned char)c]==0){
        isOk = false;
        break;
    }
  }
  std::cout << input << ":" << (isOk ? "true" : "false") << std::endl;

如果还想高效点,可以尝试下用__int128来代替上面的这个bitset。可惜java中没有128位整数。所以java.net.URI类在实现这个功能的时候,把它拆成了high mask和low mask两个long型的整数。

下面这两个函数是用来构造bitset的。(就是构造两个long)

// Compute the low-order mask for the characters in the given string
    private static long lowMask(String chars) {
        int n = chars.length();
        long m = 0;
        for (int i = 0; i < n; i++) {
            char c = chars.charAt(i);
            if (c < 64)
                m |= (1L << c);
        }
        return m;
    }

    // Compute the high-order mask for the characters in the given string
    private static long highMask(String chars) {
        int n = chars.length();
        long m = 0;
        for (int i = 0; i < n; i++) {
            char c = chars.charAt(i);
            if ((c >= 64) && (c < 128))
                m |= (1L << (c - 64));
        }
        return m;
    }

然后下面这个是match函数

// Tell whether the given character is permitted by the given mask pair
    private static boolean match(char c, long lowMask, long highMask) {
        if (c == 0) // 0 doesn't have a slot in the mask. So, it never matches.
            return false;
        if (c < 64)
            return ((1L << c) & lowMask) != 0;
        if (c < 128)
            return ((1L << (c - 64)) & highMask) != 0;
        return false;
    }

此博客中的热门博文

在windows下使用llvm+clang

少写代码,多读别人写的代码

tensorflow distributed runtime初窥