First of all, I have been using this site as a reference through the entire scripting process and it has been wonderful. I appreciate how useful and knowledgeable everyone is here. With that in mind, I have a question regarding matching (pattern matching) in Lua. I am writing a script that essentially takes input from a file and imports it into a table. I am checking for specific MAC addresses in the file as the host I am querying.
if macFile then
local file = io.open(macFile)
if file then
for line in file:lines() do
local f = line
i, j = string.find ( f, "%x+" )
m = string.sub(f, i, j)
table.insert( macTable, m )
end
file:close()
end
This parses the file into a format I will use to query later. Once the table is built, I run a pattern matching sequence to try and match the MAC from the table by iterating the table and matching the pattern against the current iteration:
local output = {}
t = "00:00:00:00:00:00"
s = string.gsub( t, ":", "")
for key,value in next,macTable,nil do
a, p = string.find ( s, value )
matchFound = string.sub(s, a, p)
table.insert( output, matchFound )
end
This doesn't return any output although when I enter it line by line in a Lua prompt, it seems to work. The variables are being passed correctly I believe. Any suggestions?
If your macFile uses a structure like this:
012345678900
008967452301
000000000000
ffffffffffff
The following script should work:
macFile = "./macFile.txt"
macTable = {}
if macFile then
local hFile = io.open(macFile, "r")
if hFile then
for line in hFile:lines() do
local _,_, sMac = line:find("^(%x+)")
if sMac then
print("Mac address matched: "..sMac)
table.insert(macTable, sMac)
end
end
hFile:close()
end
end
local output = {}
t = "00:00:00:00:00:00"
s = string.gsub( t, ":", "")
for k,v in ipairs(macTable) do
if s == v then
print("Matched macTable address: "..v)
table.insert(output, v)
end
end
I am just leaving from work and can't have a deeper look at your problem right now, but the next two lines seem quite odd.
t = "00:00:00:00:00:00"
s = string.gsub( t, ":", "")
Basically you are removing all the ':' characters in the string t. Afterwards you end up with s being "000000000000". This is probably not what you want?
Related
In Lua, Is there any good way to read Only numbers from input like "[1,2,3,4]" if i know the number of the numbers
I did io.read("*n") for each, but that just returns nil values
local num = io.read()
for i = 1, num do
print(io.read("*n"))
end
for that code inputs are
4
[1,1,15,54]
outputs are
nil
nil
nil
nil
I expect
1
1
15
54
Should I just use string.find and sub with ',' ?
If you're sure that there are no spaces in the input, you can use this code:
local num = io.read()
for i = 1, num do
io.read(1)
print(io.read("*n"))
end
The first io.read(1) reads [, the next ones read the commas. The closing ] is left unread.
Reading the whole line and parsing it is more robust:
local num = io.read()
local lin = io.read()
local i=0
for w in lin:gmatch("%d+") do
i=i+1
print(i,w)
end
Hey all I found the following code HERE and was wondering if it's possible if I can also get the line number where the word appears by using the LINQ query or by some other means?
Dim startFolder = "C:\Users\me\Documents\Visual Studio 2012\Projects\project"
Dim fileList = New System.IO.DirectoryInfo(startFolder).GetFiles("*.vb", System.IO.SearchOption.AllDirectories)
Dim queryMatchingFiles = From file In fileList _
Where file.Extension = ".vb" _
Let fileText = GetFileText(file.FullName) _
Where fileText.Contains(word2Search) _
Select file.FullName
Debug.Print("The term " & word2Search & " was found in:")
For Each filename In queryMatchingFiles
Debug.Print(filename)
Next
The code works for finding the word but I would really like to be able to know what line it was found on as well.
Any help would be great!
The LINQ Select method has a overload that passes in the index of the item.
Dim startFolder = "C:\Users\me\Documents\Visual Studio 2012\Projects\project"
Dim matches =
From f In Directory.EnumerateFiles(startFolder, "*.vb", SearchOption.AllDirectories)
From l In File.ReadLines(f).Select(Function(x, i) New With { .Line = x, .LineNo = i + 1})
Where l.Line.Contains(word2Search)
Select FileName = f, LineNo = l.LineNo, Line = l.Line
Matches will be an IEnumerable of objects with FileName, LineNo and Line properties.
UPDATE
To get the file name and an array of the matching line indexes, you could do something like this:
Dim matches =
From f In Directory.EnumerateFiles(startFolder, "*.vb", SearchOption.AllDirectories)
From l In File.ReadLines(f).Select(Function(x, i) New With { .Line = x, .LineNo = i + 1})
Where l.Line.Contains(word2Search)
Select File = f, LineNo = l.LineNo
Group By File Into g = Group
Select FileName = File, LineNos = g.Select(Function(x) x.LineNo).ToArray()
This will give you an IEnumerable of objects with FileName and LineNos properties.
Finding the positions of the matches in the lines requires a few more changes, since Contains just returns a Boolean. You can use Regex.Matches to find the positions of matches in the line, so:
Dim matches =
From f In Directory.EnumerateFiles(startFolder, "*.vb", SearchOption.AllDirectories)
From l In File.ReadLines(f).Select(Function(x, i) New With { .Line = x, .LineNo = i + 1})
Where l.Line.Contains(word2Search)
Select File = f, LineNo = l.LineNo,
MatchPositions = Regex.Matches(l.Line, Regex.Escape(word2Search)).Cast(Of Match)().Select(Function(x) x.Index)
Group By File Into g = Group
Select FileName = File, Matched = g.Select(Function(x) New With { x.LineNo, .Positions = x.MatchPositions.ToArray() }).ToArray()
After this, you end up with an IEnumerable of objects with FileName and Matched properties (unfortunately, VB.NET didn't like that being called Matches because that clashes with the matches variable, but you can play with that to your liking). The Matched property is an array of objects with LineNo and Positions properties, with Positions being an array of the indexes into the strings (zero based, so add a + 1 in there if you like).
I'm trying to match two tables by string case in sensitive.
Example
[6] =
{
["itemName"] = [Ore],
["cleanName"] = [[Iron Ingot]],
["secs"] = 25004,
["gN"] = [[Luminary]],
["buyer"] = [[#Naptha42]],
["eventType"] = 15,
["timestampz"] = 1399514069,
["quantity"] = 100,
["soldAmount"] = 500,
["seller"] = [[#FataI]],
},
I'm trying to move items from the above table format into a new table, or filter them into a list.
g = e.cleanName
for k, v in pairs(savedTable.ALL_ITEMS) do searchTable[k] = v
if g == savedTable.ALL_ITEMS.cleanName then
table.insert(searchTable, savedTable.ALL_ITEMS)
end
end
The problem above is g never = that savedTable.
The table has a few thousand entries and I'm trying to display by search, I believe the best way is to create a new table with the values im looking for?
Or is there a way to use the string.match to iterate through the table and display (print) only these values.
//Update
I have an active search, each time the user enters a letter it will search the table.
Example.
Val1 = "Hello"
Val2 = "Goodbye"
Val3 = "Hi"
While searching and the user enters "H" or "h" I want the results for "hello, hi" to show up but not "goodbye"
so with the if g == string.match(savedTable.ALL_ITEMS.cleanName)
not sure if that is correct.
//UPDATE for solution of what worked (thanks ESOUI)
local searchForItem = string.lower(g)
for k, v in ipairs(myTable.ALL_SALES) do
-- if string.lower(g) == string.lower(v.cleanName) then
if string.lower(v.cleanName):find(searchForItem) then
if v.cleanName ~= nil then
table.insert(searchTable, v)
end
end
end
If ALL_ITEMS is a table that contains tables then it isn't ever going to have a cleanName field directly.
Is that == in the loop intended to be against v?
Also, if ALL_ITEMS is integer indexed you probably want ipairs instead of pairs to walk the table in order.
Why are you inserting every element into searchTable (via searchTable[k] = v) and then also attempting to insert the matching entries again (via table.insert)?
You can use string.match to match g against the cleanName in your loop if you need to but that isn't going to solve the problem if you aren't comparing what you think you are comparing.
I´ve got a little problem. At the end of a programm it should delete a folder.
In ordern to deny deletion of a folder, which directory contains a certain word, I wanted to check if a string (the directory.fullname.tostring) contains any of the elements which are stored in a string array.
The string array contains strings stating the exception words.
This is how far I got and I know that the solution is the other way round than stated here:
If Not stackarray.Contains(dir.FullName.ToString) Then
Try
dir.Delete()
sw.WriteLine("deleting directory " + dir.FullName, True)
deldir = deldir + 1
Catch e As Exception
'write to log
sw.WriteLine("cannot delete directory " + dir.ToString + "because there are still files in there", True)
numbererror = numbererror + 1
End Try
Else
sw.WriteLine("cannot delete directory " + dir.ToString + "because it is one of the exception directories", True)
End If
Instead of checking to see if the array contains the full path, do it the other way around. Loop through all the items in the array and check if the path contains each one, for instance:
Dim isException As Boolean = False
For Each i As String In stackarray
If dir.FullName.ToString().IndexOf(i) <> -1 Then
isException = True
Exit For
End If
Next
If isException Then
' ...
End If
Or, if you want to be more fancy, you can use the Array.Exists method to do it with less lines of code, like this:
If Array.Exists(stackarray, Function(x) dir.FullName.ToString().IndexOf(x) <> -1) Then
' ...
End If
Try this :
foldersToDelete.Any(Function(folder) dir.ToLower.Contains(folder.ToLower)
You can check more info here
How do I use the Indexof Method to search for an Index a number? The number will be different on each line of the file. Each array has a name and a different zip code. I want to tell it to search for the first number in the line. Everything before that index will be first name, last name, and then zip code.
infile = IO.File.OpenText("Names.txt")
'process the loop instruct until end of file
intSubscript = 0
Do Until infile.Peek = -1
'read a line
strLine(intSubscript) = infile.ReadLine
intSubscript = intSubscript + 1
Loop
infile.Close()
A solution from how I understand this:
Instead of using the IndexOf, you can save each part of the file on a different line (ReadLine).
If you really need the IndexOf: It's just String.IndexOf(EnterCharacterHere)
You could also read this file and only use the numbers found:
First you make a const string const cstrNumbers as string = "0123456789" and then do the following:
For x as integer = 0 to strInput -1
strTemporary = strInput.Substring(x,1)
If InStr(cstrNumbers, strTemporary) <> 0 Then
strOutput &= strTemporary
strOutput will contain the numbers then.
Hope this helps,
Simon
EDIT:
This would be easier with a database, but I have no experience with db in vb.net.
You could do a substring combined with the InStr I mentioned.
First you need a function that will return the first occurrence of a number. (With InStr)
And then use this in the substring (String.SubString(FirstOccurence, LengthOfZip)
Don't have the time to do the complete code now..Hope this helps you a bit