0

I have a large registry file (30,000+ lines) where I want to be able to change two lines using Applescript. The code that I currently have takes a few minutes to finish; I was hoping there was a way to cut this down to 2 seconds or less. Is there a way to do this?

The two lines are preceded by and formatted as such (I want to change the values of the Port and Address lines):

[path\that\always\stays\the\same] <# that isn't always the same>  
"Address"="<# that isn't always the same>"
"Port"="<# that isn't always the same>"

Here is my current code adapted from this thread at MacScripter

set theFile to (((theAppResourcesFolder) as text) & "system.reg") as alias
set N to open for access theFile with write permission
get eof N
if result > 0 then
    set theText to read N
    set eof N to 0
    write deleteLinesFromText(theText, "\"Address\"", "\"Port\"", finalResultAddress, finalResultPort) to N

    --close theFile
end if
close access N

Here is deleteLinesFromText:

on deleteLinesFromText(theText, deletePhrase1, deletePhrase2, newPhrase1, newPhrase2)
set newText to ""
try
    set textList to paragraphs of theText
    repeat with i from 1 to count of textList
        set thisLine to item i of textList
        if thisLine contains deletePhrase1 then
            set newText to newText & "\"Address\"=\"" & newPhrase1 & "\"" & return
        else if thisLine contains deletePhrase2 then
            set newText to newText & "\"Port\"=\"" & newPhrase2 & "\"" & return
        else
            set newText to newText & thisLine & return
        end if
    end repeat
    if newText is not "" then set newText to text 1 thru -2 of newText

end try
return newText
end deleteLinesFromText
yannikrock
  • 55
  • 2
  • 5

2 Answers2

2

Text in AppleScript is a whole. Processing a file in lines has no benefits but sometimes can make the code better understandable. It's the same process as search and replace, but now your entire match is based on two matches and all the text in between. When setting the text item delimiters properly you can get rid of the entire loop:

set theText to "Fake text fake text fake text
\"Address\"=blah blah blah
fake text fake text fake text fake text
\"Port\"=305
fake text fake text fake text"

deleteLinesFromText(theText, "\"Address\"", "\"Port\"", "http://stackoverflow.com", 80)

on deleteLinesFromText(theText, deletePhrase1, deletePhrase2, newPhrase1, newPhrase2)
    set oldTIDs to AppleScript's text item delimiters
    set newAddress to "\"Address\"=" & newPhrase1
    set newPort to "\"Port\"=" & newPhrase2

    set AppleScript's text item delimiters to deletePhrase1
    set oldAddress to {""} & first paragraph of text item 2 of theText as string
    set AppleScript's text item delimiters to oldAddress
    set textItems to every text item of theText
    set AppleScript's text item delimiters to newAddress
    set theText to textItems as string
    set AppleScript's text item delimiters to deletePhrase2
    set oldPort to {""} & first paragraph of text item 2 of theText as string
    set AppleScript's text item delimiters to oldPort
    set textItems to every text item of theText
    set AppleScript's text item delimiters to newPort
    set theText to textItems as string

    set AppleScript's text item delimiters to oldTIDs
    return theText
end deleteLinesFromText
dj bazzie wazzie
  • 3,472
  • 18
  • 23
  • Hi DJ. I've never tested it, are TID faster with a large file as well? +1 – adayzdone Dec 12 '14 at 13:38
  • Hi adayzdone. A do shell script is slower by itself because of the overhead that is needed to invoke a shell script. Splitting it up into lines using TIDs will be slow as well because the number of text items is huge. So I split the text up into two text items keeping small lists. I've tested the code with a 2MB file (55k lines) and it took less than half a second. Of course the performance completely depends on the machine's bandwidth between storage and memory. – dj bazzie wazzie Dec 12 '14 at 14:01
1

Although sed will probably be quicker, this may shave some time off...

set newText to ""
set paraList to paragraphs of theText
repeat with thisLine in my paraList

    if thisLine contains deletePhrase1 then
        set newText to newText & "\"Address\"=\"" & newPhrase1 & "\"" & return
    else if thisLine contains deletePhrase2 then
        set newText to newText & "\"Port\"=\"" & newPhrase2 & "\"" & return
    else
        set newText to newText & thisLine & return
    end if
end repeat
if newText is not "" then set newText to text 1 thru -2 of newText
return newText
adayzdone
  • 11,120
  • 2
  • 20
  • 37
  • No "probably" about it. Using a command line tool will for sure be quicker. – jweaks Dec 11 '14 at 17:41
  • Yup... and the thread rockyan references goes into that as well. [Nigel also mentions several efficiency measures](http://macscripter.net/viewtopic.php?pid=147388#p147388) – adayzdone Dec 11 '14 at 17:53
  • Using TIDs are in general the quickest, therefore posted an example here as well. – dj bazzie wazzie Dec 12 '14 at 09:50
  • I ended up using this code, which sped things up considerably, but still took about 30 seconds (as opposed to 2 minutes). I'm considering re-thinking my entire approach. Thank you though! – yannikrock Dec 19 '14 at 14:34
  • @yannikrock: What's wrong with my code, I have tested it with a 2 meg file containing 55k lines and it worked in less than half a second. – dj bazzie wazzie Dec 19 '14 at 15:30