6

I have a search replace script which works to replace strings. It already has options to do case insensitive searches and "escaped" matches (eg allows searching for % ( etc in the search.

How ever I have now been asked to match whole words only, I have tried adding %s to each end, but that does not match words at the end of a string and I can't then work out how to trap for the white-space items found to leave them intact during the replace.

Do I need to redo the script using string.find and add logic for the word checking or this possible with patterns.

The two functions I use for case insensitive and escaped items are as follows both return the pattern to search for.

    --   Build Pattern from String for case insensitive search
function nocase (s)
      s = string.gsub(s, "%a", function (c)
            return string.format("[%s%s]", string.lower(c),
                                           string.upper(c))
          end)
      return s
    end
function strPlainText(strText)
    -- Prefix every non-alphanumeric character (%W) with a % escape character, where %% is the % escape, and %1 is original character
    return strText:gsub("(%W)","%%%1")
end 

I have a way of doing what I want now, but it's inelegant. Is there a better way?

   local strToString = ''
     local strSearchFor = strSearchi
    local strReplaceWith = strReplace
    bSkip = false
    if fhGetDataClass(ptr) == 'longtext' then
        strBoxType = 'm'
    end
   if pWhole == 1 then
    strSearchFor = '(%s+)('..strSearchi..')(%s+)'
    strReplaceWith = '%1'..strReplace..'%3'
    end
    local strToString = string.gsub(strFromString,strSearchFor,strReplaceWith)
    if pWhole == 1 then
    -- Special Case search for last word and first word
        local strSearchFor3 = '(%s+)('..strSearchi..')$'
        local strReplaceWith3 = '%1'..strReplace
        strToString = string.gsub(strToString,strSearchFor3,strReplaceWith3)
        local strSearchFor3 = '^('..strSearchi..')(%s+)'
        local strReplaceWith3 = strReplace..'%2'
        strToString = string.gsub(strToString,strSearchFor3,strReplaceWith3)
    end
Jane T
  • 2,081
  • 2
  • 17
  • 23

2 Answers2

6

have a way of doing what I want now, but it's inelegant. Is there a better way?

There is an undocumented feature of Lua's pattern matching library called the Frontier Pattern, which will let you write something like this:

function replacetext(source, find, replace, wholeword)
  if wholeword then
    find = '%f[%a]'..find..'%f[%A]'
  end
  return (source:gsub(find,replace))
end

local source  = 'test testing this test of testicular footest testimation test'
local find    = 'test'
local replace = 'XXX'
print(replacetext(source, find, replace, false))  --> XXX XXXing this XXX of XXXicular fooXXX XXXimation XXX    
print(replacetext(source, find, replace, true ))   --> XXX testing this XXX of testicular footest testimation XXX
Mud
  • 28,277
  • 11
  • 59
  • 92
2

do you mean if you pass nocase() foo, you want [fooFOO] instead of [fF][oO][oO]? if so, you could try this?

function nocase (s)
      s = string.gsub(s, "(%a+)", function (c)
            return string.format("[%s%s]", string.lower(c),
                                           string.upper(c))
          end)
      return s
end

and if you want an easy way to split a sentence into words, you can use this:

function split(strText)
    local words = {}
    string.gsub(strText, "(%a+)", function(w)
                                    table.insert(words, w)
                                  end)
    return words
end

once you've gotten the words split, it's pretty easy to iterate over the words in the table and do a full comparison against each word.

Mike Corcoran
  • 14,072
  • 4
  • 37
  • 49
  • No what I need to do is use the processed search string I have now or a variation and get it to only match whole words, so I search for "street" and it will only match "street" and not "broadstreet" – Jane T Apr 19 '12 at 16:06
  • how are you using the values you get back from nocase() and strPlainText()? that is a lot more relevant... – Mike Corcoran Apr 19 '12 at 16:22