0468. 验证IP地址 Validate IP Address

问题描述

这个是处理字符串的问题.

步骤大致如下:

  • 先检查是不是 ipv4, 如果是, 直接返回
    • 先以 . 将字符串分隔成多个部分, parts
    • parts 数组的长度应该是 4
    • 检查每一部分字符串
      • 长度在 [1..3] 之间
      • 如果以 0 为前缀的话, 只能包含 0
      • 检查里面的字符, 只能包含 0-9 这10 个字符, 可以用 std::isdigit(c)
      • 将它转换成整数, 数值范围是 [0..255]
  • 再检查是不是 ipv6, 如果是, 就返回
    • : 将字符串分隔成多个部分, parts
    • parts 数组的长度是 8
    • 检查每一部分字符串
      • 字符串长度是 [1..4] 之间
      • 检查里面的字符, 只能包含 0-9, a-f, A-F这些字符, 可以用 std::is_xdigit(c)
      • 不需要把它再转换成整数
  • 返回 Neither

以下是代码实现:

Rust

#![allow(unused)]
fn main() {
fn is_ipv4(query: &str) -> bool {
    // 用 `.` 来分隔各部分
    // 并判断每个部分是有效的数值
    // 数值不带有前缀0

    let parts: Vec<&str> = query.split('.').collect();
    if parts.len() != 4 {
        return false;
    }

    for part in parts {
        if part.is_empty() || part.len() > 3 {
            return false;
        }

        // 数值不带有前缀0
        if part.len() > 1 && part.starts_with("0") {
            return false;
        }

        // 判断字符的范围, 0-9
        for c in part.chars() {
            if !c.is_ascii_digit() {
                return false;
            }
        }

        if let Ok(val) = part.parse::<i32>() {
            // 数值范围是 0..255
            if !(0..=255).contains(&val) {
                return false;
            }
        } else {
            // 不是有效的整数
            return false;
        }
    }

    true
}

fn is_ipv6(query: &str) -> bool {
    // 使用 `:` 作为分隔符
    // 每个部分是16进制的整数, 16进制支持大小写, 最多包含4个字符
    // 可以有0作为前缀
    // 不需要考虑缩写

    let parts: Vec<&str> = query.split(':').collect();
    if parts.len() != 8 {
        return false;
    }

    for part in parts {
        // 1-4个字符
        if part.is_empty() || part.len() > 4 {
            return false;
        }

        for c in part.chars() {
            // 判断字符的范围, 0-9, a-f, A-F
            if !c.is_ascii_hexdigit() {
                return false;
            }
        }
    }

    true
}

pub fn valid_ip_address1(query_ip: String) -> String {
    if is_ipv4(&query_ip) {
        "IPv4".to_owned()
    } else if is_ipv6(&query_ip) {
        "IPv6".to_owned()
    } else {
        "Neither".to_owned()
    }
}
}

C++

#include <cassert>

#include <iostream>
#include <sstream>
#include <string>
#include <sstream>

class Solution {
 public:
  static bool isIPv4(const std::string& query) {
    // 用 `.` 来分隔各部分
    // 并判断每个部分是有效的数值
    // 数值不带有前缀0

    if (query.empty() || query[0] == '.' || query[query.size() - 1] == '.') {
      return false;
    }
    int part_count = 0;
    std::stringstream ss(query);
    std::string part;
    while (std::getline(ss, part, '.')) {
      // 数值不带有前缀0
      if (part[0] == '0' && part.size() > 1) {
        return false;
      }
      if (part.size() < 1 || part.size() > 3) {
        return false;
      }
      // 判断字符的范围, 0-9
      for (char c : part) {
        if (!std::isdigit(c)) {
          return false;
        }
      }

      size_t pos = 0;
      const int val = std::stoi(part, &pos);
      // 不是有效的整数
      if (pos != part.size()) {
        //return false;
      }

      // 数值范围是 0..255
      if (val < 0 || val > 255) {
        return false;
      }

      part_count += 1;
    }

    // 要有4个部分
    return part_count == 4;
  }

  static bool isIPv6(const std::string& query) {
    // 使用 `:` 作为分隔符
    // 每个部分是16进制的整数, 16进制支持大小写, 最多包含4个字符
    // 可以有0作为前缀
    // 不需要考虑缩写

    if (query.empty() || query[0] == ':' || query[query.size() - 1] == ':') {
      return false;
    }

    int part_count = 0;
    std::stringstream ss(query);
    std::string part;
    while (std::getline(ss, part, ':')) {
      // 1-4个字符
      if (part.size() < 1 || part.size() > 4) {
        return false;
      }

      for (char c : part) {
        // 判断字符的范围, 0-9, a-f, A-F
        if (!std::isxdigit(c)) {
          return false;
        }
      }

      part_count += 1;
    }

    return part_count == 8;
  }

  static std::string validIPAddress(std::string queryIP) {
    if (isIPv4(queryIP)) {
      return "IPv4";
    } 
    if (isIPv6(queryIP)) {
      return "IPv6";
    }
    return "Neither";
  }
};