#vb.net #file-io
#vb.net #file-io
Вопрос:
У меня есть вопрос, который просит меня вычислить что-то из входного файла. Проблема в том, что строки в файле не используют никаких специальных символов в качестве разделителя, таких как ,
или |
. Я покажу это ниже.
Data Communication
20
Visual Basic
40
Вывод, который мне нужно записать в другой файл, должен выглядеть следующим образом:
Data communication 20
Visual Basic 40
Total Books : 60
Проблема в том, как я могу указать разделитель? Например , когда есть символ , как в strArray = strLine.Split(",")
. Поскольку я ничего не могу использовать в качестве разделителя, как я могу разделить содержимое файла?
Комментарии:
1. Должно работать нормально, но это плохой способ анализа данных с разделителями, даже обычного csv.
Ответ №1:
Нет реальной необходимости разделять текст во входном файле, когда вы можете читать файл построчно, используя стандартные методы.
Вы можете использовать, например, StreamReader для чтения строк из исходного файла, проверить, является ли текущая строка просто текстом или ее можно преобразовать в число, используя Integer .Попробуйте разобрать и исключить пустые строки.
Здесь, когда прочитанная строка не является числовой, она добавляется как a Key
в a Dictionary(Of String, Integer)
, если она уже не существует (для обработки повторяющихся категорий в исходном файле).
Если строка представляет число, она добавляется к Value
соответствующей Key
ранее прочитанной категории, хранящейся в переменной с именем previousLine
.
Эта настройка может обрабатывать начальные пустые строки, пустые строки в тексте и повторяющиеся категории, например,
Data Communication
20
Visual Basic
40
C#
100
Visual Basic
10
Other stuff
2
C
10000
Other stuff
1
Если вместо этого в первой строке находится число, оно рассматривается как категория.
Добавьте любую другую проверку для обработки другой структуры входного файла.
Imports System.IO
Imports System.Linq
Dim basePath = "[Path where the input file is stored]"
Dim booksDict = New Dictionary(Of String, Integer)
Dim currentValue As Integer = 0
Dim previousLine As String = String.Empty
Using sr As New StreamReader(Path.Combine(basePath, "Books.txt"))
While sr.Peek > -1
Dim line = sr.ReadLine().Trim()
If Not String.IsNullOrEmpty(line) Then
If Integer.TryParse(line, currentValue) AndAlso (Not String.IsNullOrEmpty(previousLine)) Then
booksDict(previousLine) = currentValue
Else
If Not booksDict.ContainsKey(line) Then
booksDict.Add(line, 0)
End If
End If
End If
previousLine = line
End While
End Using
Теперь у вас есть словарь, в котором ключи представляют категории, а соответствующее значение является суммой всех книг в этой категории.
Вы можете выбрать() каждую пару KeyValuePair словаря и преобразовать ее в строку, представляющую ключ и его значение ( Category:Number
) .
Здесь также используется OrderBy() для упорядочивания категорий в алфавитном порядке по возрастанию; это может быть полезно.
Файл.Затем вызывается WriteAllLines для сохранения сгенерированных строк.
В конце к файлу добавляется новая строка с помощью File .AppendAllText , чтобы записать сумму всех книг во всех категориях. Метод Sum() суммирует все значения в словаре.
Dim newFilePath = Path.Combine(basePath, "BooksNew.txt")
File.WriteAllLines(newFilePath, booksDict.
Select(Function(kvp) $"{kvp.Key}:{kvp.Value}").OrderBy(Function(s) s))
File.AppendAllText(newFilePath, vbCrLf amp; "Total Books: " amp; booksDict.Sum(Function(kvp) kvp.Value).ToString())
Вывод:
C#:100
C :10000
Data Communication:20
Other stuff:3
Visual Basic:50
Total Books: 10173
Ответ №2:
Конечно.. System.IO.File.ReadAllLines()
прочитает весь файл и разделит на массив на основе новых строк, так что вы получите массив из 4 элементов. Вы можете обработать его с помощью логического значения flipflop, чтобы получить альтернативные строки, или вы можете попытаться разобрать строку до числа, и если это сработает, то это число, а если нет, то это строка. Если это число, возьмите строку, которую вы запомнили (используя переменную) из предыдущего цикла
Dim arr = File.ReadALlLines(...)
Dim isStr = True
Dim prevString = ""
For Each s as String in arr
If isStr Then
prevString = s
Else
Console.WriteLine($"The string is {prevString} and the number is {s}")
End If
'flip the boolean
isStr = Not isStr
Next s
Ответ №3:
Раньше я File.ReadAllLines
получал массив, содержащий каждую строку в файле. Поскольку размер файла может быть больше, чем показанный образец, я использую StringBuilder
. Это избавляет от необходимости выбрасывать и создавать новую строку на каждой итерации цикла.
Я использую интерполированные строки $
, обозначенные предшествующими кавычками. Это позволяет вставлять переменные в строку, заключенную в фигурные скобки.
Обратите Step 2
внимание на For
цикл. i
увеличится на 2 вместо 1 по умолчанию.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lines = File.ReadAllLines("input.txt")
Dim sb As New StringBuilder
Dim total As Integer
For i = 0 To lines.Length - 2 Step 2
sb.AppendLine($"{lines(i)} {lines(i 1)}")
total = CInt(lines(i 1))
Next
sb.AppendLine($"Total Books: {total}")
TextBox1.Text = sb.ToString
End Sub