8

Does anyone have an example for a search & replace lua script that I can use with TeXworks. I have a rather large document here (about 3'000 pages DIN A5) which I need to update continously. To change $to \$ and various other replacements I would like to run a 'replace-all' script which makes all the replacements in a single run.

This could be quite useful when one has to take text from e.g. MS Word or the WWW.

Uwe Ziegenhagen
  • 13,168
  • 5
  • 53
  • 93
  • 2
    Would you be interested in a sed or perl solution? – cmhughes Nov 28 '12 at 16:45
  • Nope, I would like to have one in Texworks' lua scripting. – Uwe Ziegenhagen Nov 28 '12 at 17:13
  • 1
    There is a menu item to do this with TeXworks from Search/Replace. However, I would advise you to quit TeXworks, restart, and open a new blank document to test this with first. Trying it with v4.4 on Mac hangs Texworks, and had to Force Quit to get out of this loop. – Peter Grill Nov 28 '12 at 18:21
  • @PeterGrill I know the menu command but there are various replacements I need to make, so a 'prepare for TeXing' script would be nice. It could aid a lot in the "get-text-from-somewhere-and-just-TeX" it process, replacing # => #, & => & and many more. – Uwe Ziegenhagen Nov 28 '12 at 19:34
  • @UweZiegenhagen Scripts and utilities are nice, danger when you start replacing automatically especially symbols like \& is you can end destroying some of your tables, although I guess in your case you want to clean the original MS Word document. However, in this case would be simpler to clean it in word before exporting. – yannisl Nov 28 '12 at 22:14

1 Answers1

13

Your question is very interesting, I promise to upvote it as soon as possible. As usual, I'm out of votes.

I'll try to write a humble answer. I'm really sorry if the solution might cause any trouble due to any bug or annoyance, I'm a Lua newbie. :)

First things first: we need to enable the scripting language plugin in TeXworks. We can do it by simply going to the Preferences, in the Scripts tab:

Preferences

We just need to mark the checkbox. :)

Now, let's see where to put our script. Go to Scripts, Scripting TeXworks, Show Scripts Folder:

Scripts menu

The operating system file manager will appear with the folder we want. :)

Scripts folder

In my Mac, it's under ~/Library/TeXworks/scripts. Now, create a new file named replaceList.lua and add the following content, as it is:

--[[TeXworksScript
Title: Replace list
Description: A replacement script
Author: Paulo Cereda
Version: 1.0
Date: 2012-11-28
Script-Type: standalone
Context: TeXDocument
]]

-- implements the 'strip' function in order to extract
-- elements from a string according to a specific
-- separator. The output is a table containing each
-- element from the input string.
-- Thanks to the http://lua-users.org/wiki/SplitJoin wiki.
string.split = function(str, pattern)
    pattern = pattern or "[^%s]+"    
    if pattern:len() == 0 then    
        pattern = "[^%s]+"    
    end    
    local parts = {__index = table.insert}   
    setmetatable(parts, parts)    
    str:gsub(pattern, parts)    
    setmetatable(parts, nil)   
    parts.__index = nil   
    return parts
end   

-- gets a string containing a list of patterns. This is
-- the first dialog window that appears in the script
-- execution.
local listOfPatterns = TW.getText(nil, "List of patterns to replace  - 1/2", "Please, add a list of patterns to replace, separated by comma.")

-- gets a string containing a list of words to replace the
-- patterns obtainted in the previous step. This is the
-- second dialog window that appears in the script
-- execution
local listOfReplacements = TW.getText(nil, "List of patterns to replace  - 2/2", "Please, add a list of replacements, separated by comma.")

-- checks if both inputs are valid
if (listOfPatterns ~= nil) and (listOfReplacements) then

    -- split the patterns into elements of a table. In our
    -- case, the separator is a comma.
    local patternsToLook = string.split(listOfPatterns, "[^,%s]+")

    -- split the values into elements of a table. In our case,
    -- the separator is a comma.
    local valuesToReplace = string.split(listOfReplacements, "[^,%s]+")

    -- the number of elements of both tables must be equal
    if (#patternsToLook == #valuesToReplace) then

        -- iterate through the patterns table
        for index, currentValue in ipairs(patternsToLook) do

            -- select all the text from the current
            -- document
            TW.target.selectAll();

            -- get all the selected text
            local text = TW.target.selection

            -- checks if there's actually a text
            if (text ~= nil) then

                -- replace all occurrences of the current
                -- pattern by its corresponding value
                local toReplace, _ = string.gsub(text, currentValue, valuesToReplace[index])

                -- insert modified text into the
                -- document
                TW.target.insertText(toReplace)
            end
        end 
    end
end

My sincere apologies to Patrick, Taco and other Lua masters. :)

Now, we have a new file in our folder, replaceList.lua:

New file

Now, back to TeXworks, we need to reload our list of scripts. It's easy, we need to go to Scripts, Scripting TeXworks, Reload Scripts List:

Reload scripts

Done. :) Let's create a test file:

My document

Time to run our script. Simply go to Scripts and select Replace list:

Running the script

Now, the magic of TeXworks scripting API will appear. First, we will define a list of patterns to look for:

List of patterns

Regex supported, I guess.

I'm telling our script to look for three words, separated by commas. After clicking OK, a new window will appear, with a list of replacement words:

Replacements

Of course, both lists have to have the very same size. :) After we click OK, our new text is presented:

New document

There we go! :) I hope my humble answer helps. :)

Paulo Cereda
  • 44,220
  • That looks really good and is accepted! I will try and adapt it so, that the replacement list is stored in the script itself. – Uwe Ziegenhagen Nov 28 '12 at 21:09
  • @Uwe: I added some comments to the Lua code. :) If you plan to hardcode the replacement list, I think the script will become more bulletproof - parsing the comma-separated list might be tricky, specially if special characters (used by Lua's regex) are used. – Paulo Cereda Nov 28 '12 at 22:12