Link to home
Start Free TrialLog in
Avatar of AlexeyTimofeev
AlexeyTimofeev

asked on

VB.NET Very custom for each statement

Hi there. I need to make a very custom for each statement.

As the source of information I'm using a console file of the game.

Now in that file it says SOMEPLAYER has selected a hero.

Now I need to find a players name who selected a hero. What hero is not important.
There are 10 players all together. So foreach loop has to loop through the file and search for "has selected" then it should only filter the part with the nick name and go to the next "has selected" line.

Another thing is that if player played more than one game, the program will also take 10 players from last game. To fix that I think when for each statement took first 10 player names it should store the text up to the line where he picked the last player name and then when the statement reads the log file again it should ignore all previous lines.

Same thing applies if player played 3 or 5 games in a row. I hope it is clear what I need to do.

Here is how the console writes hero selection string.

 
Line 10567: ^479[ZRG]Rutsuko^* has selected a hero.
 Line 10579: ^132Love_Him^* has selected a hero.
 Line 10594: ^521Zit0un^* has selected a hero.
 Line 10621: ^187[GEN]Rejanu^* has selected ^885Zephyr^*.
 Line 10674: ^507[GEN]Kenchik^* has selected ^885Magmus^*.
 Line 10688: ^990[2xP]SCOTU^* has selected ^885Plague Rider^*.
 Line 10700: ^950[2xP]Analcucumber^* has selected ^885Thunderbringer^*.
 Line 10702: ^029[GREM]PapaLoko^* has selected ^885Moon Queen^*.
 Line 10703: ^836[ImwS]NightyD^* has selected a hero.
 Line 10704: ^555[HUGR]Mariop4rty^* has selected a hero.

 Line 70163: ^029[GEN]Rejanu^* has selected ^885Night Hound^*.
 Line 70186: ^836[GEN]Kenchik^* has selected ^885Witch Slayer^*.

Open in new window


As you can see there are 12 lines. 10 from one game and 2 from another so it's not always 10 people in the game.... so for each statement must loop until the last "has selected" and count that as the end point. then remember it and ignore everything up to that point next time he searches through the file.
Avatar of AlexeyTimofeev
AlexeyTimofeev

ASKER

Another way would be this:

Let's say I've started first game. Console file is clean. Everyone picked heroes, and game started.

For each statement takes every "has selected" line and filters player names and stores them into the listview table or any table. For each statement remembers what line was the last "has selected" (let's say LINE 11704" and stores it into some variable. Then when it  searches for next "has selected" it starts from the line 11704 to ignore the players from last game.
do you really need to use a for each loop? Can LINQ do? What version of .NET do you want this in?
I'd rather use .NET 2.0. As far as I know LINQ is .NET 4
But if it's easier for you guys I will stick to .NET 4
Avatar of Nasir Razzaq
You can read the lines into an array and then save the index of last read and start from that index everytime

Dim MyLine As String() = GetLines() 'A dummy function to populate lines.

For i As Integer = LastIndex to MyLines.Count - 1
  ...
  LastIndex = i 'This will be the starting point next time.
Next
OK, here's the linq code suggestion. I have assumed that you have read the file into a string array (mStr). The code should be self explanatory though I have annotated it a bit.
Dim mStr As String() = {"Line 10567: ^479[ZRG]Rutsuko^* has selected a hero.",
        "Line 10579: ^132Love_Him^* has selected a hero.",
        "Line 10594: ^521Zit0un^* has selected a hero.",
        "Line 10621: ^187[GEN]Rejanu^* has selected ^885Zephyr^*.",
        "Line 10674: ^507[GEN]Kenchik^* has selected ^885Magmus^*.",
        "Line 10688: ^990[2xP]SCOTU^* has selected ^885Plague Rider^*.",
        "Line 10700: ^950[2xP]Analcucumber^* has selected ^885Thunderbringer^*.",
        "Line 10702: ^029[GREM]PapaLoko^* has selected ^885Moon Queen^*.",
        "Line 10703: ^836[ImwS]NightyD^* has selected a hero.",
        "Line 10704: ^555[HUGR]Mariop4rty^* has selected a hero.",
        "Line 70163: ^029[GEN]Rejanu^* has selected ^885Night Hound^*.",
        "Line 70186: ^836[GEN]Kenchik^* has selected ^885Witch Slayer^*."}
'the first pass
Dim Query = From j In mStr Where Not j.Contains("a hero") Select j
'this puts all the selected players into a list
Dim SelectedPlayers = (From s In Query Select s.Split(" ").Last).ToList
'the this gets the highest line number
Dim HighestNumber = (From q In Query Select CInt(q.Split(" ")(1).Replace(":", String.Empty))).Last

Open in new window

the list of selected players (and selectors?) should be either of the two below
Dim SelectedPlayers = (From s In Query Select s.Split("^")(s.Split("^").Count - 2)).ToList
Dim TheSelectors = (From s In Query Select s.Split("^")(1)).ToList

Open in new window

and how do I get out whatever is in the .tolist?
would you prefer .ToArray? The items are in the list ready for you to put to your table ....
Could you please provide me with the code of how to insert data into the table.
what would you like to copy to the table? and whatdoes your table look like?
I have datagridview with 1 field called PLAYERNAME. So I need only the name of players.

Actually I would prefer to have that information in a string format. Let's say GAME1 and then player names separated by comma. GAME2 player names etc...
I'll stick with your initial request. Here goes
Dim TheSelectors = (From s In Query Select s.Split("^")(1)).ToList
Dim PlayerTable As New DataTable("Selected Players")
PlayerTable.Columns.Add(New DataColumn With {.DataType = GetType(System.String), .ColumnName = "Players"})
Dim PlayerRow As DataRow = Nothing
For Each x In TheSelectors
    PlayerRow = PlayerTable.NewRow()
    PlayerRow.ItemArray = {x}
    PlayerTable.Rows.Add(PlayerRow)
Next
'here you can bind the table to the datagridview, e.g
DataGridView1.DataSource = PlayerTable

Open in new window

Along the lines of what CodeCruiser is suggesting.  You could loop through and keep track of the last index or "Line" (assuming that it is actually in the file right?).  Here is a regular expression based solution that might work for you. (This is .net 2.0 code, written with vs2010)

My test code:
 
Imports System.Text.RegularExpressions


Module Module1

    Private lastLineNo As Integer

    Sub Main()
        Dim strRegex As String = "^(?:Line\s+)(?<LineNo>\d+):\s+\^(?<PlayerName>[\w\[\]]+)\^\*\s+(?=(?:has selected a hero.))"
        Dim myRegexOptions As RegexOptions = RegexOptions.IgnoreCase Or RegexOptions.Multiline
        Dim myRegex As New Regex(strRegex, myRegexOptions)
        Dim strTargetString As String = IO.File.ReadAllText("C:\console.txt")
        Dim lineNo As Integer

        Dim currentPlayerNames As New List(Of String)

        For Each myMatch As Match In myRegex.Matches(strTargetString)
            If myMatch.Success Then
                If Integer.TryParse(myMatch.Groups("LineNo").Value, lineNo) AndAlso lineNo > lastLineNo Then
                    lastLineNo = lineNo
                    currentPlayerNames.Add(myMatch.Groups("PlayerName").Value)
                End If
            End If
        Next

        Dim dt As New Data.DataTable
        dt.Columns.Add("PlayerName")

        If currentPlayerNames.Count > 0 Then
            For Each plName In currentPlayerNames
                dt.Rows.Add(plName)
            Next
        End If
    End Sub

End Module

Open in new window


And the file contents of C:\console.txt:
 console.txt
Line numbers are not in the console log file... I added them up myself.
ASKER CERTIFIED SOLUTION
Avatar of Vaughn Bigham
Vaughn Bigham
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
^479 and ^132 are the color codes. I don't need them, however I don't need the clan tag also that is inside " [] ". Let's say [ZRG]. Could you fix that too please.
I also forgot to mention that the console.log file is usually in use by another application. So I need my application to be able to read it even if the file is in use.
PS. I do not save any information to the console.log file, I only need to read it.
Reading the file shouldn't be a problem for you.  Try this expression to omit the clan tags.

^\s*\^\d+(?(\[).+\]|)(?<PlayerName>[\w]+)\^\*\s+(?=has selected)
Application crashes if the console.log file is in use by the game. When I close the game it works fine.
what is the exception? and how are you reading it in? IO.File.ReadAllLines?
The process cannot access the file 'C:\Users\Rejanu\Documents\Heroes of Newerth\
game\console.log' because it is being used by another process.
I'm using exact code you gave me.
When this is solved you probably want to have a look at my other question. No one seems to be knowing the answer.

https://www.experts-exchange.com/questions/27422160/Reading-Packet-Id-from-the-Byte-array-in-the-networkstream.html?anchorAnswerId=37053131#a37053131
Can you read it in notepad while playing? The game might have opened it with FileShare.None in which case you won't have access while the game is running..  If it opened it with FileShare.Read, then you should be able to read it while playing.
I am able to open it with notepad, however my program gives an error.
Well I sort of found a workaround. I'm copying the file to the temporary location and reading it, then deleting the temporary file. Thanks for help.

Please see if you can help me with this:

https://www.experts-exchange.com/questions/27422160/Reading-Packet-Id-from-the-Byte-array-in-the-networkstream.html?anchorAnswerId=37053131#a37053131