caracter - c# convert string encoding
¿La forma más rápida de convertir un ascii byte[] posiblemente terminado en nulo a una cadena? (8)
Una posibilidad a considerar: verifique que la página de códigos predeterminada sea aceptable y use esa información para seleccionar el mecanismo de conversión en tiempo de ejecución.
Esto también podría tener en cuenta si la cadena de hecho está terminada en nulo, pero una vez que hayas hecho eso, por supuesto, la velocidad gana mi desaparición.
Necesito convertir una (posiblemente) serie terminada nula de bytes ascii a una cadena en C # y la forma más rápida que he encontrado para hacerlo es mediante el uso de mi método UnsafeAsciiBytesToString que se muestra a continuación. Este método usa el constructor String.String (sbyte *) que contiene una advertencia en sus comentarios:
"Se supone que el parámetro de valor apunta a una matriz que representa una cadena codificada utilizando la página de códigos ANSI predeterminada (es decir, el método de codificación especificado por Encoding.Default).
Nota: * Debido a que la página de códigos ANSI predeterminada depende del sistema, la cadena creada por este constructor a partir de matrices de bytes firmadas idénticas puede diferir en sistemas diferentes. * ...
* Si la matriz especificada no tiene terminación nula, el comportamiento de este constructor depende del sistema. Por ejemplo, tal situación podría causar una violación de acceso. * "
Ahora, estoy seguro de que la forma en que se codifica la cadena nunca cambiará ... pero la página de códigos predeterminada en el sistema en el que se ejecuta mi aplicación podría cambiar. Entonces, ¿hay alguna razón por la que no debería correr gritando usando String.String (sbyte *) para este propósito?
using System;
using System.Text;
namespace FastAsciiBytesToString
{
static class StringEx
{
public static string AsciiBytesToString(this byte[] buffer, int offset, int maxLength)
{
int maxIndex = offset + maxLength;
for( int i = offset; i < maxIndex; i++ )
{
/// Skip non-nulls.
if( buffer[i] != 0 ) continue;
/// First null we find, return the string.
return Encoding.ASCII.GetString(buffer, offset, i - offset);
}
/// Terminating null not found. Convert the entire section from offset to maxLength.
return Encoding.ASCII.GetString(buffer, offset, maxLength);
}
public static string UnsafeAsciiBytesToString(this byte[] buffer, int offset)
{
string result = null;
unsafe
{
fixed( byte* pAscii = &buffer[offset] )
{
result = new String((sbyte*)pAscii);
}
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
byte[] asciiBytes = new byte[]{ 0, 0, 0, (byte)''a'', (byte)''b'', (byte)''c'', 0, 0, 0 };
string result = asciiBytes.AsciiBytesToString(3, 6);
Console.WriteLine("AsciiBytesToString Result: /"{0}/"", result);
result = asciiBytes.UnsafeAsciiBytesToString(3);
Console.WriteLine("UnsafeAsciiBytesToString Result: /"{0}/"", result);
/// Non-null terminated test.
asciiBytes = new byte[]{ 0, 0, 0, (byte)''a'', (byte)''b'', (byte)''c'' };
result = asciiBytes.UnsafeAsciiBytesToString(3);
Console.WriteLine("UnsafeAsciiBytesToString Result: /"{0}/"", result);
Console.ReadLine();
}
}
}
No estoy seguro de la velocidad, pero me resultó más fácil usar LINQ para eliminar los valores nulos antes de la codificación:
string s = myEncoding.GetString(bytes.TakeWhile(b => !b.Equals(0)).ToArray());
Esto es un poco feo pero no tienes que usar un código inseguro:
string result = "";
for (int i = 0; i < data.Length && data[i] != 0; i++)
result += (char)data[i];
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestProject1
{
class Class1
{
static public string cstr_to_string( byte[] data, int code_page)
{
Encoding Enc = Encoding.GetEncoding(code_page);
int inx = Array.FindIndex(data, 0, (x) => x == 0);//search for 0
if (inx >= 0)
return (Enc.GetString(data, 0, inx));
else
return (Enc.GetString(data));
}
}
}
s = s.Substring(0, s.IndexOf((char) 0));
Una forma fácil / segura / rápida de convertir objetos byte [] a cadenas que contengan su equivalente ASCII y viceversa usando la clase .NET System.Text.Encoding. La clase tiene una función estática que devuelve un codificador ASCII:
De cadena a byte []:
string s = "Hello World!"
byte[] b = System.Text.Encoding.ASCII.GetBytes(s);
De byte [] a cadena:
byte[] byteArray = new byte[] {0x41, 0x42, 0x09, 0x00, 0x255};
string s = System.Text.Encoding.ASCII.GetString(byteArray);
Oneliner (suponiendo que el búfer en realidad contiene UNA cadena con terminación nula con formato bien):
String MyString = Encoding.ASCII.GetString(MyByteBuffer).TrimEnd((Char)0);
¿Alguna razón para no usar el String(sbyte*, int, int)
? Si ha calculado qué parte del buffer necesita, el resto debería ser simple:
public static string UnsafeAsciiBytesToString(byte[] buffer, int offset, int length)
{
unsafe
{
fixed (byte* pAscii = buffer)
{
return new String((sbyte*)pAscii, offset, length);
}
}
}
Si necesita mirar primero:
public static string UnsafeAsciiBytesToString(byte[] buffer, int offset)
{
int end = offset;
while (offset < buffer.Length && buffer[end] != 0)
{
end++;
}
unsafe
{
fixed (byte* pAscii = buffer)
{
return new String((sbyte*)pAscii, offset, end - offset);
}
}
}
Si esto realmente es una cadena ASCII (es decir, todos los bytes son menos de 128), entonces el problema de la página de códigos no debería ser un problema a menos que tenga una página de códigos predeterminada particularmente extraña que no esté basada en ASCII.
Por interés, ¿realmente ha perfilado su aplicación para asegurarse de que este es realmente el cuello de botella? ¿Definitivamente necesitas la conversión más rápida, en lugar de una que sea más legible (por ejemplo, usar Encoding.GetString para la codificación adecuada)?