2011-02-06 13 views
24

Estoy trabajando en una aplicación que importa miles de líneas, donde cada línea tiene un formato como este:C# Regex.Split: Extracción de resultados vacíos

|* 9070183020 |04.02.2011 |107222  |M/S SUNNY MEDICOS     |GHAZIABAD       |  32,768.00 | 

estoy usando el siguiente Regex para dividir las líneas a la datos que necesito:

Regex lineSplitter = new Regex(@"(?:^\|\*|\|)\s*(.*?)\s+(?=\|)"); 
string[] columns = lineSplitter.Split(data); 

foreach (string c in columns) 
    Console.Write("[" + c + "] "); 

Esto me está dando el siguiente resultado:

[] [9070183020] [] [04.02.2011] [] [107222] [] [M/S SUNNY MEDICOS] [] [GHAZIABAD] [] [32,768.00] [|] 

N ow tengo dos preguntas
1. ¿Cómo elimino los resultados vacíos? Sé que puedo utilizar:

string[] columns = lineSplitter.Split(data).Where(s => !string.IsNullOrEmpty(s)).ToArray(); 

pero ¿hay alguna construida en el método para eliminar los resultados vacíos?

2. ¿Cómo puedo eliminar la última tubería?

Gracias por cualquier ayuda.
Saludos,
Yogesh.

EDIT:
creo que mi pregunta era un poco mal entendido. Nunca fue sobre cómo puedo hacerlo. Solo fue sobre cómo puedo hacerlo cambiando el Regex en el código anterior.

Sé que puedo hacerlo de muchas maneras. Ya he hecho con el código mencionado anteriormente con una cláusula Where y con una forma alternativa que también es (más de dos veces) más rápido:

Regex regex = new Regex(@"(^\|\*\s*)|(\s*\|\s*)"); 
data = regex.Replace(data, "|"); 

string[] columns = data.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); 

segundo lugar, como un caso de prueba, mi sistema puede analizar 92K + tales líneas en menos de 1.5 segundos en el método original y en menos de 700 milisegundos en el segundo método, donde nunca encontraré más de un par de miles en casos reales, así que no creo que deba pensar en la velocidad aquí . En mi opinión, pensar en la velocidad en este caso es la optimización prematura.

he encontrado la respuesta a mi primera pregunta: ¿no se puede hacer con Split ya que no hay tal opción integrada en

Todavía estás buscando respuesta a la segunda pregunta..

+0

para responder a su primera pregunta, cree que la parte de agrupación de la expresión regular debe ser '@" (. +?) "'. De lo contrario, sería posible hacer coincidir los espacios en blanco (que es lo que tienes ahora). –

+0

No importa en este caso Jeff. Dará el mismo resultado exacto. – Yogesh

+0

Al igual que una nota cuando mencionas miles de entradas: Usar String.Split y luego hacer algo más de procesamiento de cadenas es mucho más rápido que usar una Regex en primer lugar. – Foxfire

Respuesta

37
Regex lineSplitter = new Regex(@"[\s*\*]*\|[\s*\*]*"); 
var columns = lineSplitter.Split(data).Where(s => s != String.Empty); 

o simplemente puede hacer:

string[] columns = data.Split(new char[] {'|'}, StringSplitOptions.RemoveEmptyEntries); 
foreach (string c in columns) this.textBox1.Text += "[" + c.Trim(' ', '*') + "] " + "\r\n"; 

Y no, no hay ninguna opción para eliminar las entradas vacías para RegEx.Split como está para String.split.

También puede usar coincidencias.

+0

+1 por responder mi primera pregunta. Esto también es lo que encontré leyendo en documentos net y msdn. – Yogesh

+0

Además, si prueba mi RegEx, verá que no hay valores vacíos, excepto al inicio y al final de la matriz. –

+0

Marcó su respuesta como seleccionada, ya que estuvo más cerca. Estoy usando el segundo enfoque que mencioné en mi pregunta por ser más rápido. Gracias. – Yogesh

0

¿Qué tal esto:

asumiendo que tenemos una línea:

line1="|* 9070183020 |04.02.2011 |107222  |M/S SUNNY MEDICOS     |GHAZIABAD       |  32,768.00 |"; 
resultado

podemos hemos requerido como:

string[] columns =Regex.Split(line1,"|"); 
foreach (string c in columns) 
     c=c.Replace("*","").Trim(); 

Esto dará siguiente resultado:

[9070183020] [04.02.2011] [107222] [M/S SUNNY MEDICOS] [GHAZIABAD] [32,768.00] 
0

Podría tener el wro ng idea aquí, pero solo quiere dividir la cadena data usando '|' carácter como un delimitador? En ese caso usted podría:

string[] result = data.Split(new[] { "|" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).ToArray(); 

Esto devolverá todos los campos, sin espacios y con los campos vacíos eliminados. Puede hacer lo que desee en la parte Select para formatear los resultados, p.

.Select(d => "[" + d.Trim() + "]").ToArray(); 
1

Como una alternativa a la división, que siempre va a causar problemas cuando sus delimitadores también están presentes al inicio y al final de la entrada, se puede utilizar la concordancia del contenido dentro de las tuberías:

foreach (var token in Regex.Matches(input, @"\|\*?\s*(\S[^|]*?)\s*(?=\|)")) 
{ 
    Console.WriteLine("[{0}]", token.Groups[1].Value); 
} 

// Prints the following: 
// [9070183020] 
// [04.02.2011] 
// [107222] 
// [M/S SUNNY MEDICOS] 
// [GHAZIABAD] 
// [32,768.00] 
0

Don No use una expresión regular en absoluto en su caso. Parece que no necesita uno y las expresiones regulares son mucho más lentas (y tienen una sobrecarga mucho mayor) que las funciones de cadena directamente.

a fin de utilizar algo así como:

const Char[] splitChars = new Char[] {'|'}; 

string[] splitData = data.Split(splitChars, StringSplitOptions.RemoveEmptyEntries) 
2

creo que esto puede funcionar como un equivalente para eliminar las cadenas vacías:

string[] splitter = Regex.Split(textvalue,@"\s").Where(s => s != String.Empty).ToArray<string>(); 
+0

Buen ejemplo para las pequeñas cosas que Linq mejora mucho :) –

0

Basado en @Jaroslav gran respuesta de Jandek, escribí un extension method, me ponlo aquí, tal vez puede ahorrar tu tiempo.

/// <summary> 
/// String.Split with RemoveEmptyEntries option for clean up empty entries from result 
/// </summary> 
/// <param name="s">Value to parse</param> 
/// <param name="separator">The separator</param> 
/// <param name="index">Hint: pass -1 to get Last item</param> 
/// <param name="wholeResult">Get array of split value</param> 
/// <returns></returns> 
public static object CleanSplit(this string s, char separator, int index, bool wholeResult = false) 
{ 
    if (string.IsNullOrWhiteSpace(s)) return ""; 

    var split = s.Split(new char[] { separator }, StringSplitOptions.RemoveEmptyEntries); 

    if (wholeResult) return split; 

    if (index == -1) return split.Last(); 

    if (split[index] != null) return split[index]; 

    return ""; 
} 
0

1. ¿Cómo se quita los resultados vacíos?

Puede utilizar LINQ para eliminar todas las entradas que son iguales a String.Empty:

string[] columns = lineSplitter.Split(data); 
columns = columns.ToList().RemoveAll(c => c.Equals(string.Empty)).ToArray(); 

2. ¿Cómo puedo quitar la última pipa?

Puede utilizar LINQ aquí para eliminar todas las entradas iguales al carácter que desea eliminar:

columns = columns.ToList().RemoveAll(c => c.Equals("|")).ToArray(); 
0

uso de esta solución:

string stringwithDelemeterNoEmptyValues= string.Join(",", stringwithDelemeterWithEmptyValues.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); 
Cuestiones relacionadas