Chr*_*ins 113 c# validation base64
在C#中是否有一种方法可以查看字符串是否为Base 64编码,而不仅仅是尝试转换它并查看是否存在错误?我有这样的代码:
// Convert base64-encoded hash value into a byte array.
byte[] HashBytes = Convert.FromBase64String(Value);
Run Code Online (Sandbox Code Playgroud)
我想避免如果该值不是有效的base 64字符串,则会出现"Base-64字符串中的无效字符"异常.我想检查并返回false而不是处理异常,因为我希望有时这个值不会是一个基本的64字符串.在使用Convert.FromBase64String函数之前有没有办法检查?
谢谢!
更新:
感谢您的所有答案.这是一个你可以使用的扩展方法到目前为止似乎确保你的字符串将传递Convert.FromBase64String而没有异常.当转换为base 64时,.NET似乎忽略所有尾随和结尾空格,因此"1234"有效,因此"1234"
public static bool IsBase64String(this string s)
{
s = s.Trim();
return (s.Length % 4 == 0) && Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None);
}
Run Code Online (Sandbox Code Playgroud)
对于那些对测试性能与捕获和异常感到疑惑的人来说,在大多数情况下对于这个基础64事物来说,检查比捕获异常直到达到一定长度更快.它的长度越小越快
在我非常不科学的测试中:对于字符长度100,000 - 110000的10000次迭代,它首先测试快了2.7倍.
对于字符长度为1至16个字符的1000次迭代,总共16,000次测试,它的速度提高了10.9倍.
我确信有一点可以用基于异常的方法进行测试.我只是不知道那是什么意思.
Ani*_*han 44
识别Base64字符串非常容易,因为它只会由字符组成,'A'..'Z', 'a'..'z', '0'..'9', '+', '/'并且通常最多填充两个'=',以使长度为4的倍数.但不是比较它们,而是'如果发生异常,最好忽略异常.
har*_*anb 34
我知道你说你不想抓一个例外.但是,因为捕获异常更可靠,我将继续并发布此答案.
public static bool IsBase64(this string base64String) {
// Credit: oybek https://stackoverflow.com/users/794764/oybek
if (string.IsNullOrEmpty(base64String) || base64String.Length % 4 != 0
|| base64String.Contains(" ") || base64String.Contains("\t") || base64String.Contains("\r") || base64String.Contains("\n"))
return false;
try{
Convert.FromBase64String(base64String);
return true;
}
catch(Exception exception){
// Handle the exception
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
更新:由于oybek我已经更新了条件,以进一步提高可靠性.
Tom*_*bes 27
从C#7.2使用Convert.TryFromBase64String
public static bool IsBase64String(string base64)
{
Span<byte> buffer = new Span<byte>(new byte[base64.Length]);
return Convert.TryFromBase64String(base64, buffer , out int bytesParsed);
}
Run Code Online (Sandbox Code Playgroud)
jaz*_*dev 14
我相信正则表达式应该是:
Regex.IsMatch(s, @"^[a-zA-Z0-9\+/]*={0,2}$")
Run Code Online (Sandbox Code Playgroud)
只匹配一个或两个尾随'='符号,而不是三个.
s应该是要检查的字符串.Regex是System.Text.RegularExpressions命名空间的一部分.
为什么不捕获异常,并返回False?
这避免了常见情况下的额外开销.
答案必须取决于字符串的用法。根据几位发帖人建议的语法,许多字符串可能是“有效的 base64”,但毫无例外地可能“正确”解码为垃圾。示例:8char 字符串Portland是有效的 Base64。声明这是有效的 Base64 有何意义?我想在某些时候您会想知道这个字符串应该或不应该进行 Base64 解码。
就我而言,我正在从文件 app.config 中读取 Oracle 连接字符串,该字符串可能是纯文本形式,例如:
Data source=mydb/DBNAME;User Id=Roland;Password=secret1;
Run Code Online (Sandbox Code Playgroud)
或类似base64
VXNlciBJZD1sa.....................................==
Run Code Online (Sandbox Code Playgroud)
(我的前任认为 base64 是加密:-)
为了确定是否需要进行 Base64 解码,在这个特定的用例中,我应该简单地检查字符串是否以“Data”开头(不区分大小写)。这比仅仅尝试解码并查看是否发生异常更容易、更快、更可靠:
if (ConnectionString.Substring(0, 4).ToLower() != "data")
{
//..DecodeBase64..
}
Run Code Online (Sandbox Code Playgroud)
我更新了这个答案;我以前的结论是:
我只需要检查分号是否存在,因为这证明它不是 base64,这当然比上述任何方法都要快。
仅仅为了完整起见,我想提供一些实现.一般来说,Regex是一种昂贵的方法,特别是如果字符串很大(在传输大文件时会发生).以下方法首先尝试最快的检测方法.
public static class HelperExtensions {
// Characters that are used in base64 strings.
private static Char[] Base64Chars = new[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
/// <summary>
/// Extension method to test whether the value is a base64 string
/// </summary>
/// <param name="value">Value to test</param>
/// <returns>Boolean value, true if the string is base64, otherwise false</returns>
public static Boolean IsBase64String(this String value) {
// The quickest test. If the value is null or is equal to 0 it is not base64
// Base64 string's length is always divisible by four, i.e. 8, 16, 20 etc.
// If it is not you can return false. Quite effective
// Further, if it meets the above criterias, then test for spaces.
// If it contains spaces, it is not base64
if (value == null || value.Length == 0 || value.Length % 4 != 0
|| value.Contains(' ') || value.Contains('\t') || value.Contains('\r') || value.Contains('\n'))
return false;
// 98% of all non base64 values are invalidated by this time.
var index = value.Length - 1;
// if there is padding step back
if (value[index] == '=')
index--;
// if there are two padding chars step back a second time
if (value[index] == '=')
index--;
// Now traverse over characters
// You should note that I'm not creating any copy of the existing strings,
// assuming that they may be quite large
for (var i = 0; i <= index; i++)
// If any of the character is not from the allowed list
if (!Base64Chars.Contains(value[i]))
// return false
return false;
// If we got here, then the value is a valid base64 string
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
编辑
正如Sam所建议的那样,您也可以稍微更改源代码.他为最后一步测试提供了更好的表现方法.例程
private static Boolean IsInvalid(char value) {
var intValue = (Int32)value;
// 1 - 9
if (intValue >= 48 && intValue <= 57)
return false;
// A - Z
if (intValue >= 65 && intValue <= 90)
return false;
// a - z
if (intValue >= 97 && intValue <= 122)
return false;
// + or /
return intValue != 43 && intValue != 47;
}
Run Code Online (Sandbox Code Playgroud)
可以用来替换if (!Base64Chars.Contains(value[i]))线if (IsInvalid(value[i]))
包含Sam增强功能的完整源代码将如下所示(为清晰起见,删除了注释)
public static class HelperExtensions {
public static Boolean IsBase64String(this String value) {
if (value == null || value.Length == 0 || value.Length % 4 != 0
|| value.Contains(' ') || value.Contains('\t') || value.Contains('\r') || value.Contains('\n'))
return false;
var index = value.Length - 1;
if (value[index] == '=')
index--;
if (value[index] == '=')
index--;
for (var i = 0; i <= index; i++)
if (IsInvalid(value[i]))
return false;
return true;
}
// Make it private as there is the name makes no sense for an outside caller
private static Boolean IsInvalid(char value) {
var intValue = (Int32)value;
if (intValue >= 48 && intValue <= 57)
return false;
if (intValue >= 65 && intValue <= 90)
return false;
if (intValue >= 97 && intValue <= 122)
return false;
return intValue != 43 && intValue != 47;
}
}
Run Code Online (Sandbox Code Playgroud)
解码、重新编码并将结果与原始字符串进行比较
public static Boolean IsBase64(this String str)
{
if ((str.Length % 4) != 0)
{
return false;
}
//decode - encode and compare
try
{
string decoded = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(str));
string encoded = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(decoded));
if (str.Equals(encoded, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
catch { }
return false;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
96444 次 |
| 最近记录: |