2010-10-22 4 views
2

J'ai un fichier texte généré automatiquement par un ancien système informatique quotidiennement.Recherche de l'index des caractères dans une chaîne

Malheureusement, les colonnes de ce fichier ne sont pas délimitées et leur largeur n'est pas exactement fixe (chaque jour, la largeur de chaque colonne peut changer en fonction de la quantité de caractères des données dans chaque colonne). Le fichier contient des en-têtes de colonne, donc je veux trouver la largeur de chaque colonne en utilisant les en-têtes de colonnes. Voici un exemple de l'en-tête de colonne ligne:

JOB_NO[variable amount of white space chars]FILE_NAME[variable amount of ws chars]PROJECT_CODE[variable amount of ws chars][carriage return] 

Ce que je veux faire est d'obtenir l'indice du premier caractère dans une colonne et l'indice du dernier espace blanc d'une colonne (de l'en-tête de colonne). Je voudrais obtenir l'index du "J" dans JOB_NUM et le dernier espace blanc avant le "F" dans FILE_NAME pour la première colonne. Je suppose que je devrais également mentionner que les colonnes ne peuvent pas toujours être dans le même ordre de jour en jour mais elles auront les mêmes noms d'en-tête.

Des réflexions sur comment faire cela dans VB.net ou C#? Je sais que je peux utiliser le string.indexOf ("JOB_NO") pour obtenir l'index du début de la colonne, mais comment obtenir l'index du dernier espace blanc dans chaque colonne? (ou dernier espace avant le premier non-espace suivant qui indique le début de la colonne suivante)

+0

Existe-t-il une précision [] ou est-ce juste là, par exemple, où se trouve l'espace réservé à la connaissance? – rerun

+0

non il n'y a pas de []. C'est juste par exemple de l'endroit où l'espace blanc est. – avword

Répondre

2

Obtenez les index de toutes les colonnes. par exemple.

var jPos = str.IndexOf("JOB_NO"); 
var filePos = str.IndexOf("FILE_NAME"); 
var projPos = str.IndexOf("PROJECT_CODE"); 

Puis les trier dans un tableau. de min à max. maintenant vous connaissez l'ordre de vos colonnes. le dernier espace de la première colonne est [the_next_column's_index] -1.

int firstColLastSpace = ar[1] -1; 
int secColLastSpace = ar[2] -1; 
0

fortement d'un emprunt previous answer I've given ... Pour obtenir des positions de colonne, que diriez-vous? Je fais l'hypothèse que les noms de colonnes ne contiennent pas d'espaces.

IEnumerable<int> positions=Regex 
    .Matches("JOB_NUM FILE_NAME   SOME_OTHER_THING",@"(?<=^|)\w") 
    .Cast<Match>() 
    .Select(m=>m.Index); 

ou (version bavard de ce qui précède)

//first get a MatchCollection 
//this regular expression matches a word character that immediately follows 
//either the start of the line or a space, i.e. the first char of each of 
//your column headers 
MatchCollection matches=Regex 
    .Matches("JOB_NUM FILE_NAME   SOME_OTHER_THING",@"(?<=^|)\w"); 
//convert to IEnumerable<Match>, so we can use Linq on our matches 
IEnumerable<Match> matchEnumerable=matches.Cast<Match>(); 
//For each match, select its Index 
IEnumerable<int> positions=matchEnumerable.Select(m=>m.Index); 
//convert to array (if you want) 
int[] pos_arr=positions.ToArray(); 
+0

Je suis désolé, je n'arrive pas à trouver comment utiliser la sortie de cette expression. Est-ce que "new Regex ..." renvoie une valeur? – avword

+0

J'ai réécrit ma réponse pour clarifier ce qui se passe. Il n'était pas nécessaire d'instancier une nouvelle Regex pour obtenir une MatchCollection, mais oui ... "new Regex" renvoie une nouvelle instance de Regex, sur laquelle j'appelais la méthode Matches. Comme Regex a une méthode Matches statique, il est probablement préférable de l'utiliser à la place. La sortie de l'expression est un IEnumerable . (Je l'ai indiqué dans mon édition). Vous pouvez appeler ToList ou ToArray si vous êtes plus heureux avec ces types de collection. – spender

0

Voici une autre réponse à l'aide d'une petite classe que vous pouvez utiliser plus tard pour analyser vos lignes. Vous pouvez utiliser la collection de champs comme modèle pour extraire les champs pour chacune de vos lignes, cette solution n'ignore pas les espaces car je suppose qu'ils sont variables car les champs varient en longueur chaque jour et vous auriez besoin de ces données:

Imports System.Text.RegularExpressions 

Module Module1 

    Sub Main() 

     Dim line As String = "JOB_NUM  FILE_NAME   SOME_OTHER_THING " 
     Dim Fields As List(Of Field) = New List(Of Field) 
     Dim oField As Field = Nothing 

     Dim mc As MatchCollection = Regex.Matches(
      line, "(?<=^|)\w") 

     For Each m As Match In mc 
      oField = New Field 
      oField.Start = m.Index 
      'Loop through the matches 
      If m.NextMatch.Index = 0 Then 
       'This is the last field 
       oField.Length = line.Length - oField.Start 
      Else 
       oField.Length = m.NextMatch.Index - oField.Start 
      End If 
      oField.Name = line.Substring(oField.Start, oField.Length) 
      'Trim the field name: 
      oField.Name = Trim(oField.Name) 
      'Add to the list 
      Fields.Add(oField) 
     Next 

     'Check the Fields: you can use line.substring(ofield.start, ofield.length) 
     'to parse each line of your file. 

     For Each f As Field In Fields 
      Console.WriteLine("Field Name: " & f.Name) 
      Console.WriteLine("Start: " & f.Start) 
      Console.WriteLine("Length " & f.Length) 
     Next 

     Console.Read() 
    End Sub 

    Class Field 
     Public Property Name As String 
     Public Property Start As Integer 
     Public Property Length As Integer 
    End Class 

End Module 
Questions connexes