This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
crackroach's profile picture

[Question] Finding word in a term library

Started by crackroach, 09 November 2012 - 02:06 PM
crackroach #1
Posted 09 November 2012 - 03:06 PM
I was just wondering how to look in a term library with a partly finished word. I know what i'm asking is kinda weird, but i'm trying to do something Google style.

EXAMPLE:



function google()
if (input == "cob******") then
answer = "cobblestone"
elseif (input == "red***") then
answer = "redstone"
end
end
function ask()
print("what red??") – you get the idea
input = read()

if (input == "redstone" then
print("yes")
else
google()
end
end

by the way that's only an example.
also sorry for the bad indentation, notepad++ don't like being here i guess

Clearly what i want to do is a function that propose word when yours don't match

thanks fellow lua'ers
:unsure:/>/>
Kingdaro #2
Posted 09 November 2012 - 03:31 PM
First off, protip, using
keeps indentation.

Also, this is actually sort of an interesting script. I think the best way to go about it is to have your own custom input field (using keypressing instead of read, so you can actually search for results every time the user sends a key). Then have a google() function search through a table of words, and return the ones that contain what the user has entered.


local words = {'redstone', 'cobblestone', 'dirt', 'diamond'}
local input = ''

function google(text)
	local acc = {}
	
	for i=1, #words do
		if words[i]:find(text) then
			table.insert(acc, words[i])
		end
	end
	
	return acc
end

term.setCursorBlink(true)
while true do
	-- clear the screen and print the results from the user input
	term.clear()
	term.setCursorPos(1,3)
	local results = google(input)
	
	for i=1, #results do
		print(results[i])
	end
	
	-- write the input at the top so the user knows what he typed
	term.setCursorPos(1,1)
	write(input)

	local event, param1 = os.pullEvent()
	
	-- get user input
	if event == 'char' then
		input = input .. param1
	elseif event == 'key' then
		if param1 == keys.backspace then
			input = input:sub(1, #input-1)
		end
	end
end
Espen #3
Posted 09 November 2012 - 04:15 PM
Regular Expressions are very useful for that purpose.
Quick example:
local tWordList = { "cobblestone", "redstone", "dirt", "grass", "sandstone", "sand", "stone", "stoneystoner" }
local tResults = {}

-- Input
write("Search: ")
local input = read()

-- Search for any match of input within the word-list & put it in the result table.
for _, word in pairs( tWordList ) do
    table.insert( tResults, string.match( word, ".*"..input..".*" ) )   -- This is where the the magic happens.
end

-- Output all the matches.
print("nMatches:")
for _, word in pairs( tResults ) do
    print(word)
end

Good and easily digestible reading-material regarding regular expressions with Lua: Roblox - String patterns



To explain the pattern:
. means "any character" and the * after that means "0 or more times".
So .* together means: "any character 0 or more times".

The sequence .*something.* then means:
Every string that has "something" with any amount of arbitrary characters surrounding it is a match.

For more, see the link. :unsure:/>/>
Edited on 09 November 2012 - 03:22 PM
Kingdaro #4
Posted 09 November 2012 - 04:23 PM
match() could be useful for this sort of thing, but in this situation it would probably be easier to just use find(), instead of formatting a match string.
Espen #5
Posted 09 November 2012 - 04:35 PM
Actually with find() you either only get indices and thus have to add an extra condition, or you'll have to use a regex-pattern anyway and then also need to extract the match via a capture.
So in this particular case I'd go with match() instead, because it returns the whole match directly.

But depending on how one wants to process the data further one might just as well end up with find() as the easier choice.
Ah well, many tools for many situations.^^
Kingdaro #6
Posted 09 November 2012 - 04:44 PM
Actually with find() you either only get indices and thus have to add an extra condition, or you'll have to use a regex-pattern anyway and then also need to extract the match via a capture.
So in this particular case I'd go with match() instead, because it returns the whole match directly.

But depending on how one wants to process the data further one might just as well end up with find() as the easier choice.
Ah well, many tools for many situations.^^
Indeed.
crackroach #7
Posted 10 November 2012 - 05:58 AM
wow that help a lot thanks both of you. I have an additionnal question for you, in Espen script he use


 [color="#000088"]for[/color][color="#000000"] _[/color][color="#666600"],[/color][color="#000000"] word [/color][color="#000088"]in[/color][color="#000000"] pairs[/color][color="#666600"]([/color][color="#000000"] tWordList [/color][color="#666600"])[/color] [color="#000088"]do[/color]
[color="#000088"]


why do you use the "_" for? and what is it's utility?

also i've seen" in pairs "quite few times, what is it's specificity???

I'm asking alot but since i like to program and i want to learn about it i guess asking is a good way to do so :unsure:/>/>


thanks
Espen #8
Posted 10 November 2012 - 07:16 AM
pairs() is a function that iterates through a table and returns three values for each item in the table: the next function, the table and nil.
That means you can traverse through all elements in a table like so:
for key, value in pairs(table) do
	-- do something with key and/or value
end

the variables key and value here can be any arbitrary variable name you like. The following would be just as valid:
for banana, apple in pairs(fruits) do
	-- do something with banana and/or apple
end

The first variable always represents the key and the second value always represents the value for that key.
Example: Let's say you have the following table:
local player = { firstname = "Peter", lastname = "Parker", age = 25 }

The keys would be firstname, lastname and age, whereas the value would be "Peter", "Parker" and 25.
If you'd do this …
for key, value in pairs(player) do
	print(key.." -> "..value)
end

… it would generate an output like this:
age -> 25
firstname -> Peter
lastname -> Parker

If you had a table without custom keys like this…
local fruits = { "Melon", "Orange", "Apple", "Kiwi", "Banana" }

…then the keys would be the index at which the values exist in the table and the output would look something like this:
1 -> Melon
2 -> Orange
3 -> Apple
4 -> Kiwi
5 -> Banana



Then there's ipairs() which only returns indexed values, i.e. only values that don't have a custom key.
Consider the following code:
local mixed_table = { "Marmelade", tool = "Hammer", animal = "Zebra", 23, "Bluebird", flower = "Tulip" }

for key, value in pairs(mixed_table) do
	print(key.." -> "..value)
end

This would produce an output like:
1 -> Marmelade
2 -> 23
3 -> Bluebird
flower -> Tulip
animal -> Zebra
tool -> Hammer

As you can see it listed the indexed entries first.
Now if you use ipairs() instead of pairs, the output would look like this:
1 -> Marmelade
2 -> 23
3 -> Bluebird

It only listed the indexed entries and skipped the ones with custom keys entirely.



So what is the _ character?
It's simply an arbitrary variable. In Lua an underscore is a perfectly valid variable name.
Many programmers just use _ as a crutch so that someone reading the code knows that this variable is not important and won't be used. It just acts as a placeholder.
For example, if you would only want the values of a table, you couldn't do something like this:
for value in pairs(mixed_table) do
	print(value)
end

pairs() always returns a key first and a value second. So if you only assign one variable to the output of pairs(), then whatever pairs() returns first will be stored in that variable.
That means that in the code above, value would actually always contain the current key.
If we want only the value, we have to assign our variable in second place. Ergo we have to assign some random variable in first place.
We won't need it, so it can be named anything we like. And a good way to see immediately that we only use that as a placeholder, is to use something like e.g. an underscore:
for _, value in pairs(mixed_table) do
	print(value)
end

And vice versa, i.e. if we only care about the keys and not the values, we could do this:
for key, _ in pairs(mixed_table) do
	print(value)
end

But again, it doesn't matter that we chose an underscore. You can just as well choose e.g. FUBAR:
for FUBAR, value in pairs(mixed_table) do
	print(value)
end

Since it's a perfectly valid variable name you could still make use of _ (or FUBAR) and access it whenever you like.
It's just a crutch for easier recognition by other programmers, or even yourself.

There's still a bit more detail, but this should be the gist of it.
More info:
Roblox - Core Functions: pairs
Lua PIL - pairs
Lua PIL - 7.1 Iterators and Closures
crackroach #9
Posted 11 November 2012 - 06:00 AM
Wow Espen, thanks, you're truly a walking dictionnary :unsure:/>/> very helpful, have you ever thought of making a tutorial or a library specificaly for computercraft? Taht would be awesome.

anyway thanks for the info i'm working on that program and your instruction have helped me a lot.

Also thanks to KingDaro for his bits of program, that helped a lot too.
Espen #10
Posted 11 November 2012 - 06:39 AM
I actually already did some tutorials earlier this year, albeit not that extensive ones.^^

The first one was more showcasing how to use the HTTP API.
The second was a little bit more thorough, explaining how to use CTRL+T termination prevention and how it works.
And the third one was more me musing about how one can prevent or limit disk booting.

If you'd like to take a look at what work someone has done, then you can e.g. take a look at all his/her started topics.
A very easy way to do this without searching is to click on the user's profile, then , and then "only topics" on the left side.