2012-07-06 26 views
7

Tengo datos que tiene este aspecto ...dividir una cadena en subcadenas de ancho fijo

1 TESTAAA  SERNUM A DESCRIPTION 
    2 TESTBBB  ANOTHR ANOTHER DESCRIPTION 
    3 TESTXXX  BLAHBL 

Mi pregunta es, ¿cuál es la forma más eficiente para dividir estos datos en su subseries más pequeños, ya que habrá cientos de líneas. Además, algunas de las líneas perderán la última columna. Intenté hacer expresiones regulares pero no tuve éxito con el patrón que utilicé para los anchos. Los datos anteriores deben descomponerse en estos campos (longitud de cada columna se indican a continuación)

{id} {firsttext} {serialhere} {description} 
4 22   6   30+ 

Puede alguien dar una mano o sugerir un buen patrón de expresión coincidente para extraer la información?

Gracias, Simon

Respuesta

7

Pruebe las siguientes expresiones regulares:

(.{4})(.{22})(.{6})(.+)? 

Si los valores son siempre no vacío y separados con espacios en blanco (es decir, que don' toparse uno con el otro), luego intente algo más simple como

line.Split(" ") 
6

De hecho, me recomendaría escribir un método para hacer esto a través de String.Substring directamente. Es probable que esto sea más eficiente al darle los anchos requeridos exactos.

Esto probablemente podría funcionar (aunque es no probado, y con un propósito no elimina el relleno cadena):

public static string[] SplitFixedWidth(string original, bool spaceBetweenItems, params int[] widths) 
{ 
    string[] results = new string[widths.Length]; 
    int current = 0; 

    for (int i = 0; i < widths.Length; ++i) 
    { 
     if (current < original.Length) 
     { 
      int len = Math.Min(original.Length - current, widths[i]); 
      results[i] = original.Substring(current, len); 
      current += widths[i] + (spaceBetweenItems ? 1 : 0); 
     } 
     else results[i] = string.Empty; 
    } 

    return results; 
} 

Dicho esto, si estás leyendo esto desde un archivo Stream o texto directamente, usando TextFieldParser le permitirá leer los datos directamente como datos de ancho fijo.

+0

TextFieldParse puede leer desde cualquier Stream o TextReader, s o no tiene que ir a un archivo físico. –

+0

@SteveDog Sí, los datos deben estar en un flujo. Sin embargo, esto rara vez es un problema, pero no necesariamente lo pondría allí si ya (por alguna razón) tuviera una matriz de cadenas que estuviera procesando, o algo así. Dicho esto, he editado para incluir esa información –

+0

No, estoy diciendo que tomará un TextReader también, por lo que puedes simplemente crear una instancia como 'new TextFieldParser (new StringReader (" the data "))'. No se requiere flujo –

5

Salida este enlace en MSDN:

http://msdn.microsoft.com/en-us/library/zezabash.aspx

Básicamente, la clase TextFieldParser hace exactamente este tipo de cosas. También es una gran manera de leer datos delimitados, como archivos CSV. Por alguna razón, Microsoft eligió ponerlo bajo el espacio de nombres Microsoft.VisualBasic.FileIO, lo cual es molesto porque realmente no tiene nada que ver con VB.

Por ejemplo, se puede utilizar de esta manera:

TextFieldParser parser = new TextFieldParser(new StringReader(fixedWidthData)); 
parser.TextFieldType = FieldType.FixedWidth; 
parser.SetFieldWidths(4, 22, 6, -1); 
while (!parser.EndOfData) 
{ 
    string[] row = parser.ReadFields(); 
} 
Cuestiones relacionadas