无异常地将字符串转换为 ASCII(如 TryParse)
Convert string to ASCII without exceptions (like TryParse)
我正在为 ASCII 字符串 class 实施 TryParse()
方法。该方法接受一个字符串并将其转换为 C 风格的字符串(即以 null 结尾的 ASCII 字符串)。
我一直只使用 Parse()
,使用 ::
转换为 ASCII
public static bool Parse(string s, out byte[] result)
{
result = null;
if (s == null || s.Length < 1)
return false;
byte[]d = new byte[s.Length + 1]; // Add space for null-terminator
System.Text.Encoding.ASCII.GetBytes(s).CopyTo(d, 0);
// GetBytes can throw exceptions
// (so can CopyTo() but I can replace that with a loop)
result = d;
return true;
}
但是,由于 TryParse 的想法的一部分是消除异常的开销,并且 GetBytes()
抛出异常,我正在寻找不这样做的不同方法。
也许有类似TryGetbytes()
的方法?
或者我们可以推断出标准 .Net 的预期格式 string
并以数学方式执行更改(我对 UTF 编码不太熟悉)?
编辑:我想对于字符串中的非 ASCII 字符,TryParse()
方法应该 return false
编辑:我希望当我开始为此 class 实施 ToString()
方法时,我可能需要在那里做相反的事情。
GetBytes
方法抛出异常,因为您的 Encoding.EncoderFallback
指定它应该抛出异常。
使用 EncoderReplacementFallback
创建一个编码对象以避免无法编码的字符出现异常。
Encoding encodingWithFallback = new ASCIIEncoding() { DecoderFallback = DecoderFallback.ReplacementFallback };
encodingWithFallback.GetBytes("Hɘ££o wor£d!");
这种方式模仿了原始 .NET 值类型的 TryParse
方法:
bool TryEncodingToASCII(string s, out byte[] result)
{
if (s == null || Regex.IsMatch(s, "[^\x00-\x7F]")) // If a single ASCII character is found, return false.
{
result = null;
return false;
}
result = Encoding.ASCII.GetBytes(s); // Convert the string to ASCII bytes.
return true;
}
,Encoding.GetBytes
可能抛出两种可能的异常
ArgumentNullException
很容易避免。对你的输入做一个空检查,你可以确保它永远不会被抛出。
EncoderFallbackException
需要更多调查... Reading the documentation:
A fallback strategy determines how an encoder handles invalid characters or how a decoder handles invalid bytes.
如果我们查看 documentation for ASCII encoding,我们会看到:
It uses replacement fallback to replace each string that it cannot encode and each byte that it cannot decode with a question mark ("?") character.
这意味着它不使用异常回退,因此永远不会抛出 EncoderFallbackException
。
总而言之,如果您使用 ASCII 编码并确保不传入空字符串,那么调用 GetBytes
.
将永远不会抛出异常
两个选项:
您可以完全忽略 Encoding
,自己编写循环:
public static bool TryParse(string s, out byte[] result)
{
result = null;
// TODO: It's not clear why you don't want to be able to convert an empty string
if (s == null || s.Length < 1)
{
return false;
}
byte buffer = new byte[s.Length + 1]; // Add space for null-terminator
for (int i = 0; i < s.Length; i++)
{
char c = s[i];
if (c > 127)
{
return false;
}
buffer[i] = (byte) c;
}
result = buffer;
return true;
}
这很简单,但可能比使用 Encoding.GetBytes
稍慢。
第二种选择是使用自定义 EncoderFallback
:
public static bool TryParse(string s, out byte[] result)
{
result = null;
// TODO: It's not clear why you don't want to be able to convert an empty string
if (s == null || s.Length < 1)
{
return false;
}
var fallback = new CustomFallback();
var encoding = new ASCIIEncoding { EncoderFallback = fallback };
byte buffer = new byte[s.Length + 1]; // Add space for null-terminator
// Use overload of Encoding.GetBytes that writes straight into the buffer
encoding.GetBytes(s, 0, s.Length, buffer, 0);
if (fallback.HadErrors)
{
return false;
}
result = buffer;
return true;
}
虽然这需要编写 CustomFallback
- 它需要基本上跟踪是否曾被要求处理无效输入。
如果您不介意编码处理两次数据,您可以使用基于 UTF-8 的编码调用 Encoding.GetByteCount
并使用替换回退(使用非 ASCII 替换字符),然后检查returns 字节数是否与字符串中的字符数相同。如果是,请调用 Encoding.ASCII.GetBytes
.
我个人会选择第一个选项,除非您有理由相信它太慢。
我正在为 ASCII 字符串 class 实施 TryParse()
方法。该方法接受一个字符串并将其转换为 C 风格的字符串(即以 null 结尾的 ASCII 字符串)。
我一直只使用 Parse()
,使用 ::
public static bool Parse(string s, out byte[] result)
{
result = null;
if (s == null || s.Length < 1)
return false;
byte[]d = new byte[s.Length + 1]; // Add space for null-terminator
System.Text.Encoding.ASCII.GetBytes(s).CopyTo(d, 0);
// GetBytes can throw exceptions
// (so can CopyTo() but I can replace that with a loop)
result = d;
return true;
}
但是,由于 TryParse 的想法的一部分是消除异常的开销,并且 GetBytes()
抛出异常,我正在寻找不这样做的不同方法。
也许有类似TryGetbytes()
的方法?
或者我们可以推断出标准 .Net 的预期格式 string
并以数学方式执行更改(我对 UTF 编码不太熟悉)?
编辑:我想对于字符串中的非 ASCII 字符,TryParse()
方法应该 return false
编辑:我希望当我开始为此 class 实施 ToString()
方法时,我可能需要在那里做相反的事情。
GetBytes
方法抛出异常,因为您的 Encoding.EncoderFallback
指定它应该抛出异常。
使用 EncoderReplacementFallback
创建一个编码对象以避免无法编码的字符出现异常。
Encoding encodingWithFallback = new ASCIIEncoding() { DecoderFallback = DecoderFallback.ReplacementFallback };
encodingWithFallback.GetBytes("Hɘ££o wor£d!");
这种方式模仿了原始 .NET 值类型的 TryParse
方法:
bool TryEncodingToASCII(string s, out byte[] result)
{
if (s == null || Regex.IsMatch(s, "[^\x00-\x7F]")) // If a single ASCII character is found, return false.
{
result = null;
return false;
}
result = Encoding.ASCII.GetBytes(s); // Convert the string to ASCII bytes.
return true;
}
Encoding.GetBytes
可能抛出两种可能的异常
ArgumentNullException
很容易避免。对你的输入做一个空检查,你可以确保它永远不会被抛出。
EncoderFallbackException
需要更多调查... Reading the documentation:
A fallback strategy determines how an encoder handles invalid characters or how a decoder handles invalid bytes.
如果我们查看 documentation for ASCII encoding,我们会看到:
It uses replacement fallback to replace each string that it cannot encode and each byte that it cannot decode with a question mark ("?") character.
这意味着它不使用异常回退,因此永远不会抛出 EncoderFallbackException
。
总而言之,如果您使用 ASCII 编码并确保不传入空字符串,那么调用 GetBytes
.
两个选项:
您可以完全忽略 Encoding
,自己编写循环:
public static bool TryParse(string s, out byte[] result)
{
result = null;
// TODO: It's not clear why you don't want to be able to convert an empty string
if (s == null || s.Length < 1)
{
return false;
}
byte buffer = new byte[s.Length + 1]; // Add space for null-terminator
for (int i = 0; i < s.Length; i++)
{
char c = s[i];
if (c > 127)
{
return false;
}
buffer[i] = (byte) c;
}
result = buffer;
return true;
}
这很简单,但可能比使用 Encoding.GetBytes
稍慢。
第二种选择是使用自定义 EncoderFallback
:
public static bool TryParse(string s, out byte[] result)
{
result = null;
// TODO: It's not clear why you don't want to be able to convert an empty string
if (s == null || s.Length < 1)
{
return false;
}
var fallback = new CustomFallback();
var encoding = new ASCIIEncoding { EncoderFallback = fallback };
byte buffer = new byte[s.Length + 1]; // Add space for null-terminator
// Use overload of Encoding.GetBytes that writes straight into the buffer
encoding.GetBytes(s, 0, s.Length, buffer, 0);
if (fallback.HadErrors)
{
return false;
}
result = buffer;
return true;
}
虽然这需要编写 CustomFallback
- 它需要基本上跟踪是否曾被要求处理无效输入。
如果您不介意编码处理两次数据,您可以使用基于 UTF-8 的编码调用 Encoding.GetByteCount
并使用替换回退(使用非 ASCII 替换字符),然后检查returns 字节数是否与字符串中的字符数相同。如果是,请调用 Encoding.ASCII.GetBytes
.
我个人会选择第一个选项,除非您有理由相信它太慢。