from - C#StreamReader, "ReadLine" para delimitadores personalizados
streamreader excel c# (4)
Aquí hay un analizador simple que utilicé donde lo necesitaba (generalmente, si la transmisión no es primordial, solo lea y. Splice hace el trabajo), no demasiado optimizado, pero debería funcionar bien:
(es más un método de división como, y más notas a continuación)
public static IEnumerable<string> Split(this Stream stream, string delimiter, StringSplitOptions options)
{
var buffer = new char[_bufffer_len];
StringBuilder output = new StringBuilder();
int read;
using (var reader = new StreamReader(stream))
{
do
{
read = reader.ReadBlock(buffer, 0, buffer.Length);
output.Append(buffer, 0, read);
var text = output.ToString();
int id = 0, total = 0;
while ((id = text.IndexOf(delimiter, id)) >= 0)
{
var line = text.Substring(total, id - total);
id += delimiter.Length;
if (options != StringSplitOptions.RemoveEmptyEntries || line != string.Empty)
yield return line;
total = id;
}
output.Remove(0, total);
}
while (read == buffer.Length);
}
if (options != StringSplitOptions.RemoveEmptyEntries || output.Length > 0)
yield return output.ToString();
}
... y simplemente puede cambiar a delimitadores de caracteres si es necesario simplemente reemplace el
while ((id = text.IndexOf(delimiter, id)) >= 0)
...con
while ((id = text.IndexOfAny(delimiters, id)) >= 0)
(y id++
lugar de id+=
y una firma de this Stream stream, StringSplitOptions options, params char[] delimiters
)
... también elimina vacío, etc.
Espero eso ayude
¿Cuál es la mejor manera de tener la funcionalidad del método StreamReader.ReadLine()
, pero con delimitadores personalizados (String)?
Me gustaría hacer algo como:
String text;
while((text = myStreamReader.ReadUntil("my_delim")) != null)
{
Console.WriteLine(text);
}
Intenté hacer mi propio uso de Peek()
y StringBuilder
, pero es demasiado ineficiente. Estoy buscando sugerencias o posiblemente una solución de código abierto.
Gracias.
Editar
Debería haber aclarado esto antes ... He visto esta respuesta , sin embargo, preferiría no leer el archivo completo en la memoria.
Este código debería funcionar para cualquier separador de cadenas.
public static IEnumerable<string> ReadChunks(this TextReader reader, string chunkSep)
{
var sb = new StringBuilder();
var sepbuffer = new Queue<char>(chunkSep.Length);
var sepArray = chunkSep.ToCharArray();
while (reader.Peek() >= 0)
{
var nextChar = (char)reader.Read();
if (nextChar == chunkSep[sepbuffer.Count])
{
sepbuffer.Enqueue(nextChar);
if (sepbuffer.Count == chunkSep.Length)
{
yield return sb.ToString();
sb.Length = 0;
sepbuffer.Clear();
}
}
else
{
sepbuffer.Enqueue(nextChar);
while (sepbuffer.Count > 0)
{
sb.Append(sepbuffer.Dequeue());
if (sepbuffer.SequenceEqual(chunkSep.Take(sepbuffer.Count)))
break;
}
}
}
yield return sb.ToString() + new string(sepbuffer.ToArray());
}
Renuncia:
Hice ReadLine
pruebas sobre esto y en realidad es más lento que el método ReadLine
, pero sospecho que se debe a las llamadas en cola / dequeue / sequenceEqual que se pueden evitar en el método ReadLine
(porque el separador siempre es /r/n
).
Una vez más, hice algunas pruebas y debería funcionar, pero no lo tomo como perfecto y no dude en corregirlo. ;)
Pensé que publicaría mi propia solución. Parece funcionar bastante bien y el código es relativamente simple. Siéntete libre de comentar
public static String ReadUntil(this StreamReader sr, String delim)
{
StringBuilder sb = new StringBuilder();
bool found = false;
while (!found && !sr.EndOfStream)
{
for (int i = 0; i < delim.Length; i++)
{
Char c = (char)sr.Read();
sb.Append(c);
if (c != delim[i])
break;
if (i == delim.Length - 1)
{
sb.Remove(sb.Length - delim.Length, delim.Length);
found = true;
}
}
}
return sb.ToString();
}
public static String ReadUntil(this StreamReader streamReader, String delimiter)
{
StringBuilder stringBuilder = new StringBuilder();
while (!streamReader.EndOfStream)
{
stringBuilder.Append(value: (Char) streamReader.Read());
if (stringBuilder.ToString().EndsWith(value: delimiter))
{
stringBuilder.Remove(stringBuilder.Length - delimiter.Length, delimiter.Length);
break;
}
}
return stringBuilder.ToString();
}