RegExp _email = RegExp( r"^((([a-z]|\d|[!#\$%&'*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$"); RegExp _phoneNumber = RegExp(r'^(84|0[3|5|7|8|9])+([0-9]{8})\b$'); RegExp _ipv4Maybe = RegExp(r'^(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)\.(\d?\d?\d)$'); RegExp _ipv6 = RegExp(r'^::|^::1|^([a-fA-F0-9]{1,4}::?){1,7}([a-fA-F0-9]{1,4})$'); RegExp _creditCard = RegExp( r'^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$'); /// check if the string [str] is an email bool isEmail(String str) { return _email.hasMatch(str.toLowerCase()); } bool isPhoneNumber(String str) { return _phoneNumber.hasMatch(str.toLowerCase()); } T? shift(List l) { if (l.isNotEmpty) { // ignore: always_specify_types final first = l.first; l.removeAt(0); return first; } return null; } /// check if the string [str] is a URL /// /// * [protocols] sets the list of allowed protocols /// * [requireTld] sets if TLD is required /// * [requireProtocol] is a `bool` that sets if protocol is required for validation /// * [allowUnderscore] sets if underscores are allowed /// * [hostWhitelist] sets the list of allowed hosts /// * [hostBlacklist] sets the list of disallowed hosts bool isURL(String? str, {List protocols = const ['http', 'https', 'ftp'], bool requireTld = true, bool requireProtocol = false, bool allowUnderscore = false, List hostWhitelist = const [], List hostBlacklist = const []}) { if (str == null || str.isEmpty || str.length > 2083 || str.startsWith('mailto:')) { return false; } int port; String? protocol, auth, user; String host, hostname, portStr, path, query, hash; // check protocol var split = str.split('://'); if (split.length > 1) { protocol = shift(split); if (!protocols.contains(protocol)) { return false; } } else if (requireProtocol == true) { return false; } str = split.join('://'); // check hash split = str.split('#'); str = shift(split); hash = split.join('#'); if (hash.isNotEmpty && RegExp(r'\s').hasMatch(hash)) { return false; } // check query params split = str!.split('?'); str = shift(split); query = split.join('?'); if (query.isNotEmpty && RegExp(r'\s').hasMatch(query)) { return false; } // check path split = str!.split('/'); str = shift(split); path = split.join('/'); if (path.isNotEmpty && RegExp(r'\s').hasMatch(path)) { return false; } // check auth type urls split = str!.split('@'); if (split.length > 1) { auth = shift(split); if (auth?.contains(':') ?? false) { user = shift(auth!.split(':'))!; if (!RegExp(r'^\S+$').hasMatch(user)) { return false; } if (!RegExp(r'^\S*$').hasMatch(user)) { return false; } } } // check hostname hostname = split.join('@'); split = hostname.split(':'); host = shift(split)!; if (split.isNotEmpty) { portStr = split.join(':'); try { port = int.parse(portStr, radix: 10); } catch (e) { return false; } if (!RegExp(r'^[0-9]+$').hasMatch(portStr) || port <= 0 || port > 65535) { return false; } } if (!isIP(host, null) && !isFQDN(host, requireTld: requireTld, allowUnderscores: allowUnderscore) && host != 'localhost') { return false; } if (hostWhitelist.isNotEmpty && !hostWhitelist.contains(host)) { return false; } if (hostBlacklist.isNotEmpty && hostBlacklist.contains(host)) { return false; } return true; } /// check if the string [str] is IP [version] 4 or 6 /// /// * [version] is a String or an `int`. bool isIP(String? str, int? version) { if (version == null) { return isIP(str, 4) || isIP(str, 6); } else if (version == 4) { if (!_ipv4Maybe.hasMatch(str!)) { return false; } var parts = str.split('.'); parts.sort((a, b) => int.parse(a) - int.parse(b)); return int.parse(parts[3]) <= 255; } return version == 6 && _ipv6.hasMatch(str!); } /// check if the string [str] is a fully qualified domain name (e.g. domain.com). /// /// * [requireTld] sets if TLD is required /// * [allowUnderscore] sets if underscores are allowed bool isFQDN(String str, {bool requireTld = true, bool allowUnderscores = false}) { var parts = str.split('.'); if (requireTld) { var tld = parts.removeLast(); if (parts.isEmpty || !RegExp(r'^[a-z]{2,}$').hasMatch(tld)) { return false; } } for (var part in parts) { if (allowUnderscores) { if (part.contains('__')) { return false; } } if (!RegExp(r'^[a-z\\u00a1-\\uffff0-9-]+$').hasMatch(part)) { return false; } if (part[0] == '-' || part[part.length - 1] == '-' || part.contains('---')) { return false; } } return true; } /// check if the string is a credit card bool isCreditCard(String str) { var sanitized = str.replaceAll(RegExp(r'[^0-9]+'), ''); if (!_creditCard.hasMatch(sanitized)) { return false; } // Luhn algorithm var sum = 0; String digit; var shouldDouble = false; for (var i = sanitized.length - 1; i >= 0; i--) { digit = sanitized.substring(i, (i + 1)); var tmpNum = int.parse(digit); if (shouldDouble == true) { tmpNum *= 2; if (tmpNum >= 10) { sum += ((tmpNum % 10) + 1); } else { sum += tmpNum; } } else { sum += tmpNum; } shouldDouble = !shouldDouble; } return (sum % 10 == 0); } /// check if the string is a date bool isDate(String str) { try { DateTime.parse(str); return true; } catch (e) { return false; } }