if not modules then modules = { } end modules ['l-string'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } local string = string local sub, gmatch, format, char, byte, rep, lower = string.sub, string.gmatch, string.format, string.char, string.byte, string.rep, string.lower local lpegmatch, patterns = lpeg.match, lpeg.patterns local P, S, C, Ct, Cc, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cs -- Some functions are already defined in l-lpeg and maybe some from here will -- move there (unless we also expose caches). -- if not string.split then -- -- function string.split(str,pattern) -- local t = { } -- if #str > 0 then -- local n = 1 -- for s in gmatch(str..pattern,"(.-)"..pattern) do -- t[n] = s -- n = n + 1 -- end -- end -- return t -- end -- -- end -- function string.unquoted(str) -- return (gsub(str,"^([\"\'])(.*)%1$","%2")) -- interesting pattern -- end local unquoted = patterns.squote * C(patterns.nosquote) * patterns.squote + patterns.dquote * C(patterns.nodquote) * patterns.dquote function string.unquoted(str) return lpegmatch(unquoted,str) or str end -- print(string.unquoted("test")) -- print(string.unquoted([["t\"est"]])) -- print(string.unquoted([["t\"est"x]])) -- print(string.unquoted("\'test\'")) -- print(string.unquoted('"test"')) -- print(string.unquoted('"test"')) function string.quoted(str) return format("%q",str) -- always double quote end function string.count(str,pattern) -- variant 3 local n = 0 for _ in gmatch(str,pattern) do -- not for utf n = n + 1 end return n end function string.limit(str,n,sentinel) -- not utf proof if #str > n then sentinel = sentinel or "..." return sub(str,1,(n-#sentinel)) .. sentinel else return str end end local stripper = patterns.stripper local fullstripper = patterns.fullstripper local collapser = patterns.collapser local longtostring = patterns.longtostring function string.strip(str) return lpegmatch(stripper,str) or "" end function string.fullstrip(str) return lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) return lpegmatch(collapser,str) or "" end function string.longtostring(str) return lpegmatch(longtostring,str) or "" end -- function string.is_empty(str) -- return not find(str,"%S") -- end local pattern = P(" ")^0 * P(-1) -- maybe also newlines -- patterns.onlyspaces = pattern function string.is_empty(str) if str == "" then return true else return lpegmatch(pattern,str) and true or false end end -- if not string.escapedpattern then -- -- local patterns_escapes = { -- ["%"] = "%%", -- ["."] = "%.", -- ["+"] = "%+", ["-"] = "%-", ["*"] = "%*", -- ["["] = "%[", ["]"] = "%]", -- ["("] = "%(", [")"] = "%)", -- -- ["{"] = "%{", ["}"] = "%}" -- -- ["^"] = "%^", ["$"] = "%$", -- } -- -- local simple_escapes = { -- ["-"] = "%-", -- ["."] = "%.", -- ["?"] = ".", -- ["*"] = ".*", -- } -- -- function string.escapedpattern(str,simple) -- return (gsub(str,".",simple and simple_escapes or patterns_escapes)) -- end -- -- function string.topattern(str,lowercase,strict) -- if str == "" then -- return ".*" -- else -- str = gsub(str,".",simple_escapes) -- if lowercase then -- str = lower(str) -- end -- if strict then -- return "^" .. str .. "$" -- else -- return str -- end -- end -- end -- -- end --- needs checking local anything = patterns.anything local allescapes = Cc("%") * S(".-+%?()[]*") -- also {} and ^$ ? local someescapes = Cc("%") * S(".-+%()[]") -- also {} and ^$ ? local matchescapes = Cc(".") * S("*?") -- wildcard and single match local pattern_a = Cs ( ( allescapes + anything )^0 ) local pattern_b = Cs ( ( someescapes + matchescapes + anything )^0 ) local pattern_c = Cs ( Cc("^") * ( someescapes + matchescapes + anything )^0 * Cc("$") ) function string.escapedpattern(str,simple) return lpegmatch(simple and pattern_b or pattern_a,str) end function string.topattern(str,lowercase,strict) if str=="" or type(str) ~= "string" then return ".*" elseif strict then str = lpegmatch(pattern_c,str) else str = lpegmatch(pattern_b,str) end if lowercase then return lower(str) else return str end end -- print(string.escapedpattern("12+34*.tex",false)) -- print(string.escapedpattern("12+34*.tex",true)) -- print(string.topattern ("12+34*.tex",false,false)) -- print(string.topattern ("12+34*.tex",false,true)) function string.valid(str,default) return (type(str) == "string" and str ~= "" and str) or default or nil end -- handy fallback string.itself = function(s) return s end -- also handy (see utf variant) local pattern_c = Ct( C(1) ^0) -- string and not utf ! local pattern_b = Ct((C(1)/byte)^0) function string.totable(str,bytes) return lpegmatch(bytes and pattern_b or pattern_c,str) end -- handy from within tex: local replacer = lpeg.replacer("@","%%") -- Watch the escaped % in lpeg! function string.tformat(fmt,...) return format(lpegmatch(replacer,fmt),...) end -- obsolete names: string.quote = string.quoted string.unquote = string.unquoted