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.
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.
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^*.
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.
do you really need to use a for each loop? Can LINQ do? What version of .NET do you want this in?
ASKER
I'd rather use .NET 2.0. As far as I know LINQ is .NET 4
ASKER
But if it's easier for you guys I will stick to .NET 4
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
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
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
ASKER
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 ....
ASKER
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?
ASKER
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...
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
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:
And the file contents of C:\console.txt:
console.txt
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
And the file contents of C:\console.txt:
console.txt
ASKER
Line numbers are not in the console log file... I added them up myself.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
^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.
ASKER
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.
ASKER
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+(?(\[).+\]|)(?<Pl ayerName>[ \w]+)\^\*\ s+(?=has selected)
^\s*\^\d+(?(\[).+\]|)(?<Pl
ASKER
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?
ASKER
The process cannot access the file 'C:\Users\Rejanu\Documents \Heroes of Newerth\
game\console.log' because it is being used by another process.
game\console.log' because it is being used by another process.
ASKER
I'm using exact code you gave me.
ASKER
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
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.
ASKER
I am able to open it with notepad, however my program gives an error.
ASKER
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
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
ASKER
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.