Help with a multiple text replacement script

Even though this forum so far has been for sharing scripts and not for writing them, I was wondering if I could pick the brains of AHK experts ( and  come to mind right now), to figure something out.

I'm trying to put together a script to do multiple text replacements at a segment level, i.e., for the active segment only, so I can easily see what has been changed, without calling up the Find & Replace window.

I've managed to put together this script (silly examples included):

#r::
ClipSaved := ClipboardAll
Clipboard =
SendInput, ^a^c
ClipWait, 30
FixString := Clipboard
vList := " ;continuation section
(
dog perro

house casa
¿ ¿
/ /
, ,
? ?
. .
pie 2 pie2
m 2 m2
)"
Loop, Parse, vList, `n
{
oTemp := StrSplit(A_LoopField, "`t")
FixString := StrReplace(FixString, oTemp.1, oTemp.2)
}
oTemp := ""
Clipboard := FixString ; load the new string to clipboard
Sleep 200
Send ^v
Return

This works fine in segments with no tags, but when there are tags, they get stripped at some point during the replacement operation and the text that is pasted back into the segment has all the necessary replacements but no tags. Is there any way of preserving the tags in the clipboard?

I came up with a very clumsy workaround for this, which involves using Studio's Delete to Next Tag shortcut, so instead of Select All-Copy, the script would do Delete to Next Tag-Undo-Copy:

#r::
ClipSaved := ClipboardAll
Clipboard =
;SendInput, ^a^c
;ClipWait, 30
Send ^+D ;delete to next tag
Sleep 100
Send ^z ;undo
Sleep 50
Send ^c
ClipWait, 30
FixString := Clipboard
vList := " ;continuation section
(
organisation organization
¿ ¿
/ /
, ,
? ?
. .
pie 2 pie2
m 2 m2
)"
Loop, Parse, vList, `n
{
oTemp := StrSplit(A_LoopField, "`t")
FixString := StrReplace(FixString, oTemp.1, oTemp.2)
}
oTemp := ""
Clipboard := FixString ; load the new string to clipboard
Sleep 200
Send ^v
Return

While this also works in segments with no tags, I would like to optimize it.

My second question is: how would I go about creating a list of all these replacements (CSV? Excel?) and getting the script to take them from there instead of having to add them manually to the script? I've been reading up on arrays but I'm still far away from being able to implement what I need.

I have another simpler script attempt with just multiple StringReplace lines (see below), but again, that would require creating possibly hundreds of replacement lines and I imagine it's not the best solution.

#p:: 
Send, ^a
Send, ^c
StringReplace, clipboard, clipboard, dog, perro, All
StringReplace, clipboard, clipboard, cat, gato, All
StringReplace, clipboard, clipboard, raining, lloviendo, All
Send ^v
Return

So, any help with this would be greatly appreciated.

Thank you!

Parents
  • Hi Nora,

    I'll start with some suggestions to your second question about how to better implement the search and replacement items:

    Separating search and replacement parts by a tab is smart, but you don't need to put these into your script. It is way easier to maintain a simple text file where you add them and then read that text file into a variable like this:

    FileRead, vList, vListFile.txt

    In order to run your search and replace, just use a simple loop:

    Send, ^a
    Send, ^c

    Loop, Parse, vList, `r, `n
    {
        oTemp := StrSplit(A_LoopField, "`t")
        FixString := StrReplace(FixString, oTemp.1, oTemp.2)
    }

    SendInput, %FixString%

    As for the tag question, I need to look a bit deeper into this, but I fear it won't be easy without (again) the help of Studio APIs.

    Kind regards,
    Raphaël

  • Dear Raphaël Toussaint, dear Nora Díaz,

    thanks a lot for your script. I have the same problem as Nora and wanted to use such a script while maintaining an external file where the terms to be replaced are.

    However, I am doing something wrong and it doesn't work. My script is the following:

    ___________________________

    #r::
    ClipSaved := ClipboardAll
    Clipboard =

    FileRead, vList, vListFile.txt

    Send, ^a
    Send, ^c
    Loop, Parse, vList, `r, `n
    {
        oTemp := StrSplit(A_LoopField, "`t")
        FixString := StrReplace(FixString, oTemp.1, oTemp.2)
    }
    SendInput, %FixString%

    ;Sleep 200
    ;Send ^v
    Return

    __________________________

    The file vListFile.txt is in the same folder and reads:

    dog    perro
    house    casa

    (There is a tab after dog and after house.)

    __________________________

    • I have an example file open which reads:

    This is a dog and that is a house.

    • I press Windows + R.

    The text is only shortly highlighted and unhighlighted, but «dog» isn't changed to «perro» and «house» not to «casa».

    What am I doing wrong in the script?

    Please help!

    Best regards

    Robert

    emoji
  •  

    I think you missed this important line just before the loop:

    FixString := Clipboard

    emoji
  • Dear Jesús,

    thanks a lot for your answer! That line made my script work.

    I made the script more complete so that it directly copies source to target and applies the word replacement list before sending the content to a machine translation:

    ^#ü::
    ClipSaved := ClipboardAll
    Clipboard =

    FileRead, vList, vListFile.txt
    Send, ^{Ins}
    Send, ^a
    Send, ^c
    FixString := Clipboard
    Loop, Parse, vList, `r, `n
    {
        oTemp := StrSplit(A_LoopField, "`t")
        FixString := StrReplace(FixString, oTemp.1, oTemp.2)
    }
    SendInput, %FixString%

    Sleep 200
    Send, {ctrl down}ä{ctrl up}

    ; This "Ctrl + ä" is for the actual machine translation in an external program like e.g. «KeyCtrl».
    Return

    ----

    However, the script is rather slow when filling in word by word and replacing the words from the replacement list. Then it stops and doesn't complete the additional steps. Any idea to make the replacement process quicker?

    I appreciate any help!

    Cheers

    Rob

    emoji
  •  

    Just for fun I put your exact post into ChatGPT.  I have no idea if the response is correct and have not attempted to test it... but I am curious.  Maybe it'll work, but if not perhaps there will be something in the answer that could be helpful for you:

    ^#ü::
    ClipSaved := ClipboardAll
    Clipboard =
    
    FileRead, vList, vListFile.txt
    Send, ^{Ins}
    Send, ^a
    Send, ^c
    ClipWait, 2 ; Wait for clipboard to be populated
    if ErrorLevel {
        MsgBox, 48, Error, Clipboard was not populated within 2 seconds.
        return
    }
    
    FixString := Clipboard
    
    ; Build a dictionary for faster lookup
    ReplacementDict := {}
    Loop, Parse, vList, `r, `n
    {
        oTemp := StrSplit(A_LoopField, "`t")
        ReplacementDict[oTemp.1] := oTemp.2
    }
    
    ; Replace words using the dictionary
    FixString := RegExReplace(FixString, "\b\w+\b", Func("ReplaceWords"))
    
    SendInput, %FixString%
    
    Sleep 200
    Send, {ctrl down}ä{ctrl up}
    Return
    
    ReplaceWords(m) {
        global ReplacementDict
        word := m.Value
        if (ReplacementDict.HasKey(word)) {
            return ReplacementDict[word]
        }
        return word
    }
    

    Here are the main optimizations used in this script:

    1. Use ClipWait to ensure the clipboard is populated before proceeding with the script.
    2. Build a dictionary (associative array) with the replacement list for faster word lookups.
    3. Use RegExReplace with a function object to handle word replacements more efficiently.

    These optimizations should make the replacement process quicker and allow the script to complete the additional steps.

    emoji
Reply
  •  

    Just for fun I put your exact post into ChatGPT.  I have no idea if the response is correct and have not attempted to test it... but I am curious.  Maybe it'll work, but if not perhaps there will be something in the answer that could be helpful for you:

    ^#ü::
    ClipSaved := ClipboardAll
    Clipboard =
    
    FileRead, vList, vListFile.txt
    Send, ^{Ins}
    Send, ^a
    Send, ^c
    ClipWait, 2 ; Wait for clipboard to be populated
    if ErrorLevel {
        MsgBox, 48, Error, Clipboard was not populated within 2 seconds.
        return
    }
    
    FixString := Clipboard
    
    ; Build a dictionary for faster lookup
    ReplacementDict := {}
    Loop, Parse, vList, `r, `n
    {
        oTemp := StrSplit(A_LoopField, "`t")
        ReplacementDict[oTemp.1] := oTemp.2
    }
    
    ; Replace words using the dictionary
    FixString := RegExReplace(FixString, "\b\w+\b", Func("ReplaceWords"))
    
    SendInput, %FixString%
    
    Sleep 200
    Send, {ctrl down}ä{ctrl up}
    Return
    
    ReplaceWords(m) {
        global ReplacementDict
        word := m.Value
        if (ReplacementDict.HasKey(word)) {
            return ReplacementDict[word]
        }
        return word
    }
    

    Here are the main optimizations used in this script:

    1. Use ClipWait to ensure the clipboard is populated before proceeding with the script.
    2. Build a dictionary (associative array) with the replacement list for faster word lookups.
    3. Use RegExReplace with a function object to handle word replacements more efficiently.

    These optimizations should make the replacement process quicker and allow the script to complete the additional steps.

    emoji
Children
  • Hi Paul,

    thanks for your efforts. I really appreciate it.

    However, now I get results like:

    "               ,       ." or "    ,       ." or "        ." (only spaces + comma and period).

    I also tried the script when putting

    Sleep 200
    Send, {ctrl down}ä{ctrl up}
    Return

    at the end because this "Ctrl+ä" is the actual machine translation and should be after the word replacement function, I think. But I get the same wrong results...

    Maybe, Jesús Prieto, you can help here?

    Kind regards

    Rob

    emoji
  • Hi ,

    However, now I get results like

    As Paul said, it’s just ChatGPT code and you still need to confirm it’s good or not and take the bits you find useful.

    However, the script is rather slow when filling in word by word and replacing the words from the replacement list.
    How big is your your list of replacements? With a list of 6 replacements, the full loop runs around 50,000 times per second. So unless your list is really huge, this shouldn't be an issue.
    I believe the bottlenecks are the steps of inserting Source in Target, selecting the Target segment, copying Target to the clipboard and sending the replaced text to the Target segment.
    Then it stops and doesn't complete the additional steps.
    So I understand this line doesn't work, right?
    Send, {ctrl down}ä{ctrl up}
    Which external program is it?
    Does it work if you press CTRL+Ä keys in Trados Studio? 
    Do you need to have the text selected in Target before pressing CTRL+Ä? If you do, you'll need to add some lines to your AutoHotkey script,
    Does the external program automatically pastes the MT text in Target after pressing CTRL+Ä? If it doesn't, you'll need to add some lines to the AutoHotkey script,
    Is the Ä key available on your keyboard or you need to press a dead key?
    BTW; I don't quite understand why you run Machine Translation on an already replaced text…
    emoji