Module:Str find word: Difference between revisions

Content deleted Content added
No edit summary
Undid revision 1147915801 by Lemondoge (talk): oh dear. I checked with testcases - don't know how this goofed
 
(81 intermediate revisions by 4 users not shown)
Line 1:
require('strict')
-- STABLE: 12-11-2021 14:30
require('Module:No globals')
local p = {}
local getArgs = require('Module:Arguments').getArgs
local str = require('Module:String')
local yesno = require('Module:Yesno')
local sSepdefaultSep = ', '
local iMaxWords = 16
local warningIMaxWordsReached = nil
local xpLitWordCount = 0
local warningMaxWordcountReached = false
local report -- to be initinated when explain needed
 
-- Initialise the /report subpage.
-- only invoked when needed when 'explain' asked
local function initReport()
report = require('Module:User:DePiep/sfwStr find word/report')
end
 
-- Turn "A" into "A" etc. asap
-- and reduce multi-spaces (including nbsp etc.) into single space
local function decodeUnicode(str)
Line 32:
-- step 1: when case-insensitive, turn string into lowercase
-- step 2: read & remove Literals ("..")
-- step 3: readsread comma-separated words
-- step 4: when booleans=T, change boolean words into true/false (module:yesno rules)
-- all words returned are trimmed, TODO and all ws into single-plainspace?
-- only T/F words are edited, other words remain, untouched:
-- return the table (simplea straight array)
local function buildWordTableCSVbuildWordTable(newAtArgs, sWordlist)
-- step 2 uses function str._match(s, pattern, start, match_index, plain_flag, nomatch)
local function buildWordTableCSV(newA, sWordlist)
local wordTable = {}
local hitWord = ''
Line 45 ⟶ 44:
 
-- Step 1: case-sensitive
if yesno(newAtArgs.case, falsetrue) == false then
sWordlist = string.lower(sWordlist)
end
Line 52 ⟶ 51:
-- then remove them from the string:
-- replaced by single comma; idle & keeps word separation
--- if yesno(newAtArgs.literals, false) then
if newA.booleansfalse then
local _, sCount
_, sCount = mw.ustring.gsub(sWordlist, '"', '')
Line 78:
-- Step 3: parse comma-delimited words
hitCount = 0
sWordlist = tArgs.sep .. sWordlist .. tArgs.sep
while hitCount < 9 do
local eSep
eSep = escape_word(tArgs.sep)
local patstring = '%f[^' .. eSep .. '][^' .. eSep .. ']+%f[' .. eSep .. ']'
if yesno(newAtArgs.explain, truefalse) then
report.xpMessage('1.eSep: ' .. eSep) -- dev
report.xpMessage('2.pattern: ' .. patstring) -- dev
end
while hitCount <= 9iMaxWords do
hitCount = hitCount + 1
hitWord = str._match(',' .. sWordlist .. ',', '%f[^,][^,]+%f[,]'patstring, 1, hitCount, false, ','tArgs.sep)
hitWord = mw.text.trim(hitWord)
if hitWord == ','tArgs.sep then
-- no more words found in the string
break
Line 89 ⟶ 98:
end
end
if hitCount > 8iMaxWords then
warningMaxWordcountReachedwarningIMaxWordsReached = 'Max number of words (16' .. tostring(iMaxWords) .. ') reached,. extraExtra words might beare ignored.'
.. ' (' .. mw.ustring.sub(mw.text.trim(sWordlist), 1, 90) .. '&nbsp;...). '
end
 
-- Step 4: when read booleans, converse to words to true/false
-- todo: check parameter here not elsewhere
if newA.booleans then
if tArgs.booleans then -- TODO if Yesno(tArgs.booleans) ...
local sBool
for i, v in ipairs(wordTable) do
Line 152 ⟶ 163:
bAND = true
end
 
return bAND, tHits
end
Line 190 ⟶ 201:
-- Determine the requested return value (string).
-- sYeslist is the _main return value (logically defined value)
-- this function applies newAtArgs.yes / newAtArgs.no return value
-- note: yes='' implies: blank return value
-- note: no parameter yes= (that is, yes=nil) implies: by default, return the sYeslist
local function yesnoReturnstring(newAtArgs, sYeslist)
if sYeslist == '' then -- False
return newAtArgs.no or ''
else -- True
if newAtArgs.yes == nil then
return sYeslist
else -- some |yes= value is entered, could be ''
return newAtArgs.yes
end
end
Line 207 ⟶ 218:
local function isPreview()
local ifPreview = require('Module:If preview')
return not (ifPreview._warning( {'is_preview'} ) == '')
end
 
Line 214 ⟶ 225:
-- explain=true => show report in Preview
-- explain=testcases => WHEN in ns: template: or user: AND subpage = '/testcases' THEN show permanently
local function checkExplain(newAtArgs)
return false -- never. 22Mar2023 checkExplain(newArgs)
if yesno(newA.explain, true) then
if yesno(newA.explain, false) == true then -- explicit True so preview show
if isPreview() == true then
return true
end
elseif newA.explain == 'testcases' then
local titleObj = mw.title.getCurrentTitle()
if titleObj:inNamespaces('template', 'user')
and titleObj.subpageText == 'testcases'
and titleObj.isSubpage then
return 'testcases'
end
end
end
return false
end
 
Line 242 ⟶ 239:
-- 3. final conclusion drawn (T/F)
-- 4. optionally, the preview report is prepared (debug, feedback)
-- 5. based on T or F status, the return value (string) is buildestablished and returned
-- note 1: each return value (yes=.., no=..) can be '' (nulstring)
function p._main(newAtArgs)
local sourceWordTable = {}
local andWordTable = {}
Line 256 ⟶ 253:
local sYeslist = ''
 
sourceWordTable = buildWordTableCSVbuildWordTable(newAtArgs, newAtArgs.source)
andWordTable = buildWordTableCSVbuildWordTable(newAtArgs, newAtArgs.andString)
orWordTable = buildWordTableCSVbuildWordTable(newAtArgs, newAtArgs.orString)
 
if (#sourceWordTable == 0) or (#andWordTable + #orWordTable == 0) then
-- noNo words to check
resultALL = false
if yesno(newAtArgs.explain, truefalse) then
report.xpNoWords(newAtArgs, sourceWordTable, andWordTable, orWordTable)
end
else
Line 276 ⟶ 273:
-- concat the sYeslist (= all hit words; from 2 tables)
if bANDresult then
sYeslist = sYeslist .. table.concat(tANDhits, sSeptArgs.sep)
end
 
if #tORhits > 0 then
if #tANDhits > 0 then
sYeslist = sYeslist .. sSeptArgs.sep
end
sYeslist = sYeslist .. table.concat(tORhits, sSeptArgs.sep)
end
end
if yesno(newAtArgs.explain, truefalse) then
if newAtArgs.yes ~= nil then
if (newAtArgs.yes == '') and (newAtArgs.no == '') then
report.xpYesNoBothBlank()
end
end
if warningIMaxWordsReached ~= nil then
report.xpBuildReport(newA, sourceWordTable,
report.xpMessage(warningIMaxWordsReached)
end
report.xpBuildReport(newAtArgs, sourceWordTable,
bANDresult, andWordTable, tANDhits,
bORresult, orWordTable, tORhits,
sYeslist, xpLitWordCount, warningMaxWordcountReached)
end
return yesnoReturnstring(newAtArgs, sYeslist)
end
 
-- set wordt separator
local function setSep(sSep)
if sSep == nil then return defaultSep end
local msg = ''
-- todo what with {{!}}
local newSep = defaultSep
 
newSep = sSep
sSep = decodeUnicode(sSep)
if string.match(sSep, '[%s%w%d]') ~= nil then -- not ok
msg = 'Irregular characters in sep: ' .. sSep
newSep = defaultSep
end
newSep = string.sub(sSep, 1, 1)
if newSep == '' then --- ???
newSep = defaultSep
end
return truenewSep
end
 
local function concatAndLists(s1, s2, newSep)
local tLists = {} -- working table: both s1 and s2 to concat
table.insert(tLists, s1)
table.insert(tLists, s2)
return table.concat(tLists, sSepnewSep)
end
 
local function parseArgs(origArgs)
local newArgs = {}
newArgs['sep'] = setSep(origArgs['sep']) -- do first, needed below
newArgs['source'] = decodeUnicode(origArgs['s'] or origArgs['source'] or '')
newArgs['andString'] = decodeUnicode(concatAndLists(
origArgs['w'] or origArgs['word'] or nil,
origArgs['andw'] or origArgs['andwords'] or nil)),
newArgs.sSep)
)
newArgs['orString'] = decodeUnicode(origArgs['orw'] or origArgs['orwords'] or '')
-- boolean options: catch both parameters, also handle nil & nonsense input values:
newArgs['case'] = yesno(origArgs['case'] or origArgs['casesensitive'] or falsetrue, falsetrue) -- defaults to FalseTrue
newArgs['booleans'] = yesno(origArgs['bool'] or origArgs['booleans'] or false, false) -- defaults to False
newArgs['literals'] = yesno(origArgs['literals'] or origArgs['lit'] or true, true) -- defaults to True
newArgs['yes'] = origArgs['yes'] or nil -- nil; default so return sYeslist; keep '' as legal input & return value
newArgs['no'] = origArgs['no'] or ''
newArgs['explain'] = origArgs['explain']false or-- falsenever. 22Mar2023 checkExplain(newArgs)
 
newArgs.explain = false -- never. 22Mar2023 checkExplain(newArgs)
return newArgs
Line 331 ⟶ 355:
local origArgs = getArgs(frame)
local sReturn = ''
local newAtArgs = {}
 
newAtArgs = parseArgs(origArgs)
if yesno(newAtArgs.explain, truefalse) then
initReport()
report.xpListArguments(origArgs)
end
 
sReturn = p._main(newAtArgs)
if warningIMaxWordsReached ~=nil then
local preview = require('Module:NoIf globalspreview')
sReturn = sReturn .. preview._warning({warningIMaxWordsReached})
end
 
if yesno(newAtArgs.explain, truefalse) then
return sReturn .. report.xpPresent(newAtArgs.explain)
else
return sReturn