if not modules then modules = { } end modules ['publ-fnd'] = { version = 1.001, comment = "this module part of publication support", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local tonumber, next = tonumber, next local P, R, C, Cs, Cp, Carg = lpeg.P, lpeg.R, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Carg local lpegmatch = lpeg.match local concat = table.concat local formatters = string.formatters local lowercase = characters.lower local colon = P(":") local dash = P("-") local lparent = P("(") local rparent = P(")") local space = lpeg.patterns.whitespace local valid = 1 - colon - space - lparent - rparent ----- key = C(valid^1) local key = C(R("az","AZ")^1) local word = Cs(lpeg.patterns.unquoted + valid^1) local number = C(valid^1) ----- f_string_key = formatters[" local s_%s = entry[%q]"] local f_string_key = formatters[" local s_%s = entry[%q] if s_%s then s_%s = lower(s_%s) end "] local f_number_key = formatters[" local n_%s = tonumber(entry[%q]) or 0"] local f_field_key = formatters[" local f_%s = entry[%q] or ''"] ----- f_string_match = formatters["(s_%s and find(lower(s_%s),%q))"] local f_string_match = formatters["(s_%s and find(s_%s,%q))"] local f_number_match = formatters["(n_%s and n_%s >= %s and n_%s <= %s)"] local f_field_match = formatters["f_%s"] local match = key * (colon/"") * word * Carg(1) / function(key,_,word,keys) -- keys[key] = f_string_key(key,key) keys[key] = f_string_key(key,key,key,key,key) return f_string_match(key,key,lowercase(word)) end local range = key * (colon/"") * number * (dash/"") * number * Carg(1) / function(key,_,first,_,last,keys) keys[key] = f_number_key(key,key) return f_number_match(key,key,tonumber(first) or 0,key,tonumber(last) or 0) end local field = (P("field:")/"") * key * Carg(1) / function(_,key,keys) keys[key] = f_field_key(key,key) return f_field_match(key) end ----- pattern = Cs((field + range + match + P(1))^1) ----- b_match = P("match")/"" * lparent local b_match = lparent local e_match = rparent * space^0 * P(-1) local pattern = Cs(b_match * ((field + range + match + space + P(1))-e_match)^1 * e_match) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- local tolower = lpeg.patterns.tolower local lower = string.lower local allascii = R("\000\127")^1 * P(-1) function characters.checkedlower(str) return lpegmatch(allascii,str) and lower(str) or lpegmatch(tolower,str) or str end -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- local f_template = string.formatters[ [[ local find = string.find local lower = characters.checkedlower return function(entry) %s return %s and true or false end ]] ] local function compile(expr,start) local keys = { } local expression = lpegmatch(pattern,expr,start,keys) -- print("!!!!",expression) local definitions = { } for k, v in next, keys do definitions[#definitions+1] = v end definitions = concat(definitions,"\n") local code = f_template(definitions,expression) -- print(code) code = loadstring(code) if type(code) == "function" then code = code() if type(code) == "function" then return code end end print("no valid expression",expression) return false end local cache = { } -- todo: make weak, or just remember the last one (trial typesetting) local check = P("match") * space^0 * Cp() local function finder(expression) local found = cache[expression] if found == nil then local e = lpegmatch(check,expression) found = e and compile(expression,e) or false cache[expression] = found end return found end publications.finder = finder function publications.search(dataset,expression) local find = finder(expression) local source = dataset.luadata if find then local target = { } for k, v in next, source do if find(v) then target[k] = v end end return target else return { source[expression] } end end -- local dataset = publications.new() -- publications.load(dataset,"t:/manuals/hybrid/tugboat.bib") -- -- local n = 500 -- -- local function test(dataset,str) -- local found -- local start = os.clock() -- for i=1,n do -- found = search(dataset,str) -- end -- local elapsed = os.clock() - start -- print(elapsed,elapsed/500,#table.keys(dataset.luadata),str) -- print(table.concat(table.sortedkeys(found)," ")) -- return found -- end -- -- local found = test(dataset,[[match(author:hagen)]]) -- local found = test(dataset,[[match(author:hagen and author:hoekwater and year:1990-2010)]]) -- local found = test(dataset,[[match(author:"Bogusław Jackowski")]]) -- local found = test(dataset,[[match(author:"Bogusław Jackowski" and (tonumber(field:year) or 0) > 2000)]]) -- local found = test(dataset,[[Hagen:TB19-3-304]]) -- 1.328 0.002656 2710 author:hagen -- Berdnikov:TB21-2-129 Guenther:TB5-1-24 Hagen:TB17-1-54 Hagen:TB19-3-304 Hagen:TB19-3-311 Hagen:TB19-3-317 Hagen:TB22-1-58 Hagen:TB22-3-118 Hagen:TB22-3-136 Hagen:TB22-3-160 Hagen:TB23-1-49 Hagen:TB25-1-108 Hagen:TB25-1-48 Hagen:TB26-2-152 -- 1.812 0.003624 2710 author:hagen and author:hoekwater and year:1990-2010 -- Berdnikov:TB21-2-129 -- 1.344 0.002688 2710 author:"Bogusław Jackowski" -- Berdnikov:TB21-2-129 Jackowski:TB16-4-388 Jackowski:TB19-3-267 Jackowski:TB19-3-272 Jackowski:TB20-2-104 Jackowski:TB24-1-64 Jackowski:TB24-3-575 Nowacki:TB19-3-242 Rycko:TB14-3-171 -- 1.391 0.002782 2710 author:"Bogusław Jackowski" and (tonumber(field:year) or 0) > 2000 -- Jackowski:TB24-1-64 Jackowski:TB24-3-575