gsub and multiple-replacement

Discussion in 'Ruby' started by Greg Hacke, May 10, 2011.

  1. Greg Hacke

    Greg Hacke Guest

    So I have a file that I am replicating per user.
    I'm copying the file,

    Profile_path='/path/to/file/'
    Profile_file='myfile.txt'
    copy(Profile_path + Profile_file, Profile_path + username + '.txt')

    This obviously goes off without a hitch. Now, I need to find and replace
    three specific values within the file itself.

    So within the file we have:

    Record for {username} with {email} from {country}

    I've read through a ton of material and am looking for the best method.
    Here are a few caveats:
    I don't need a temp file.
    I am unconcerned with overwriting the username.txt file with itself.
    I have to replace three values within the file.

    Basically, I want to do something like:

    text = File.read(Profile_path+username+'.txt')
    File.open(Profile_path+username+'.txt','w+){|f| f <<
    text.gsub(regex_to_find,
    text_to_put_in_place)}

    But what is the best way to do this for three variables?

    --
    Posted via http://www.ruby-forum.com/.
     
    Greg Hacke, May 10, 2011
    #1
    1. Advertising

  2. Greg Hacke

    7stud -- Guest

    > Here are a few caveats:
    > I don't need a temp file.


    Yes, you do.

    > I am unconcerned with overwriting the username.txt file with itself.


    Ok, you still need a tempfile.

    Now, if you say you are unconcerned with losing all the data in your
    file, then you don't need a tempfile.

    The bottom line is this: you don't replace anything in a file. Instead,
    you read in the original file, and write out the altered lines to a new
    file. When you are done, you can delete the original file and rename
    the new file to the old file name.

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, May 10, 2011
    #2
    1. Advertising

  3. On Tue, May 10, 2011 at 11:16 PM, Greg Hacke <> wrote:
    >
    > This obviously goes off without a hitch. Now, I need to find and replace
    > three specific values within the file itself.
    >
    > So within the file we have:
    >
    > Record for {username} with {email} from {country}
    >
    > =A0I've read through a ton of material and am looking for the best method=
     
    Phillip Gawlowski, May 10, 2011
    #3
  4. Greg Hacke

    7stud -- Guest

    require 'stringio'

    str =<<'ENDOFSTRING'
    Record for WendyQ with from Germany
    Record for bohH with from USA
    ENDOFSTRING

    file = StringIO.new(str)
    file.each do |line|
    words = line.split(' ')
    words[2] = '***'
    words[4] = '***'
    words[6] = '***'

    puts words.join(' ')
    end

    --output:--
    Record for *** with *** from ***
    Record for *** with *** from ***

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, May 10, 2011
    #4
  5. Greg Hacke

    Greg Hacke Guest

    7stud -- wrote in post #997852:

    OK, I think it would be better to be a bit more specific...

    User logs into site. Credentials are verified via LDAP.

    At login, I am copying a .mobileconfig template file (xml/plist) and
    saving it as {username}.profile.mobileconfig
    This file contains placeholders for:
    {username} =
    {userroot} = bob
    {password} = mypassword

    I need to read it, modify it, save it and replace it. At that point, the
    user will get the index and be afforded to download this file.

    Thoughts?

    --
    Posted via http://www.ruby-forum.com/.
     
    Greg Hacke, May 11, 2011
    #5
  6. Greg Hacke

    7stud -- Guest

    Greg Hacke wrote in post #997877:
    > 7stud -- wrote in post #997852:
    >
    > OK, I think it would be better to be a bit more specific...
    >
    > User logs into site. Credentials are verified via LDAP.
    >
    > At login, I am copying a .mobileconfig template file (xml/plist) and
    > saving it as {username}.profile.mobileconfig
    > This file contains placeholders for:
    > {username} =
    > {userroot} = bob
    > {password} = mypassword
    >
    > I need to read it, modify it, save it and replace it. At that point, the
    > user will get the index and be afforded to download this file.
    >
    > Thoughts?


    Yeah, what is so hard about posting a sample of the original file, as
    well as the modified file that you want to end up with, and leaving out
    all your confusing analysis?

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, May 11, 2011
    #6
  7. On Wed, May 11, 2011 at 2:49 AM, Greg Hacke <> wrote:
    > 7stud -- wrote in post #997852:
    >
    > OK, I think it would be better to be a bit more specific...
    >
    > User logs into site. Credentials are verified via LDAP.
    >
    > At login, I am copying a .mobileconfig template file (xml/plist) and
    > saving it as {username}.profile.mobileconfig
    > This file contains placeholders for:
    > =A0{username} =3D
    > =A0{userroot} =3D bob
    > =A0{password} =3D mypassword
    >
    > I need to read it, modify it, save it and replace it. At that point, the
    > user will get the index and be afforded to download this file.
    >
    > Thoughts?


    How big is the file? Is it acceptable to have it all in memory?
    Do you have control over the format of the placeholders? If so, I'd go
    with Philip's suggestion of using ERB. Just change {username} to <%=3D
    username %> and evaluate the template with a binding that contains a
    variable username. For example:


    username =3D "Bob"
    password =3D "pwd"
    expanded_file =3D ERB.new(File.read("template.erb"), nil, "%<>").result(bin=
    ding)

    template.erb:

    The user is <%=3D username %>
    The password is <%=3D password %>

    Jesus.
     
    Jesús Gabriel y Galán, May 11, 2011
    #7
  8. Greg Hacke

    Greg Hacke Guest

    7stud -- wrote in post #997885:
    >
    > Yeah, what is so hard about posting a sample of the original file, as
    > well as the modified file that you want to end up with, and leaving out
    > all your confusing descriptions?


    OK, here's the inbound:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>PayloadContent</key>
    <array>
    <dict>
    <key>EmailAddress</key>
    <string>{username}</string>
    <key>Host</key>
    <string>exchange.domain.com</string>
    <key>MailNumberOfPastDaysToSync</key>
    <integer>3</integer>
    <key>Password</key>
    <string>{password}</string>
    <key>PayloadDescription</key>
    <string>Configures device for use with Microsoft Exchange
    ActiveSync services.</string>
    <key>PayloadDisplayName</key>
    <string>Exchange</string>
    <key>PayloadIdentifier</key>
    <string>com.domain.enterprise.eas</string>
    <key>PayloadOrganization</key>
    <string>TipsHouse</string>
    <key>PayloadType</key>
    <string>com.apple.eas.account</string>
    <key>PayloadUUID</key>
    <string>FE477C13-BF4F-4EA0-BE09-3968EC40C952</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>SSL</key>
    <true/>
    <key>UserName</key>
    <string>domain\{userroot}</string>
    </dict>
    </array>
    <key>PayloadDescription</key>
    <string>Profile Test</string>
    <key>PayloadDisplayName</key>
    <string>TipsHouse</string>
    <key>PayloadIdentifier</key>
    <string>com.domain.enterprise</string>
    <key>PayloadOrganization</key>
    <string>Domain</string>
    <key>PayloadRemovalDisallowed</key>
    <false/>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadUUID</key>
    <string>A6B7D66D-1179-4E85-A005-4DAACD4EDF0F</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    </dict>
    </plist>

    And the outbound replaces elements in only the array area (in this case,
    just the EAS but other options may be included - LDAP, IMAP, etc.)
    <dict>
    <key>EmailAddress</key>
    <string></string>
    <key>Host</key>
    <string>exchange.domain.com</string>
    <key>MailNumberOfPastDaysToSync</key>
    <integer>3</integer>
    <key>Password</key>
    <string>MyPassword</string>
    <key>PayloadDescription</key>
    <string>Configures device for use with Microsoft Exchange
    ActiveSync services.</string>
    <key>PayloadDisplayName</key>
    <string>Exchange</string>
    <key>PayloadIdentifier</key>
    <string>com.domain.enterprise.eas</string>
    <key>PayloadOrganization</key>
    <string>TipsHouse</string>
    <key>PayloadType</key>
    <string>com.apple.eas.account</string>
    <key>PayloadUUID</key>
    <string>FE477C13-BF4F-4EA0-BE09-3968EC40C952</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
    <key>SSL</key>
    <true/>
    <key>UserName</key>
    <string>domain\greghacke</string>
    </dict>

    Now, the initial file is provided to me may be replaced as needed. I
    would like to avoid converting it to ERb as I cannot gaurentee anyone
    else will do the work to ensure it stays updated and correct.

    I've dug around - really - and found two examples for single element
    replacement.

    My belief is that there are a plethora of options execute this. I would
    like to do something like:
    File.copy(master,user_file)
    File.open('/tmp/temp_file.txt', 'w+') do | new_file |
    new_file.puts(File.open(user_file, 'r') do | original_file |
    original_file.read.gsub(/\{username\}/, username)
    end)
    end
    FileUtils.mv("/tmp/replaceable2.txt", user_file)

    text= File.read user_file
    File.open(user_file, 'w+'){|f| f << text.gsub(/\{username\}/,
    username)}

    --
    Posted via http://www.ruby-forum.com/.
     
    Greg Hacke, May 11, 2011
    #8
  9. On Wed, May 11, 2011 at 3:45 PM, Greg Hacke <> wrote:
    > 7stud -- wrote in post #997885:
    >>
    >> Yeah, what is so hard about posting a sample of the original file, as
    >> well as the modified file that you want to end up with, and leaving out
    >> all your confusing descriptions?

    >
    > OK, here's the inbound:
    > <?xml version=3D"1.0" encoding=3D"UTF-8"?>
    > <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
    > "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    > <plist version=3D"1.0">
    > <dict>
    > =A0<key>PayloadContent</key>
    > =A0<array>
    > =A0 =A0<dict>
    > =A0 =A0 =A0<key>EmailAddress</key>
    > =A0 =A0 =A0<string>{username}</string>
    > =A0 =A0 =A0<key>Host</key>
    > =A0 =A0 =A0<string>exchange.domain.com</string>
    > =A0 =A0 =A0<key>MailNumberOfPastDaysToSync</key>
    > =A0 =A0 =A0<integer>3</integer>
    > =A0 =A0 =A0<key>Password</key>
    > =A0 =A0 =A0<string>{password}</string>
    > =A0 =A0 =A0<key>PayloadDescription</key>
    > =A0 =A0 =A0<string>Configures device for use with Microsoft Exchange
    > ActiveSync services.</string>
    > =A0 =A0 =A0<key>PayloadDisplayName</key>
    > =A0 =A0 =A0<string>Exchange</string>
    > =A0 =A0 =A0<key>PayloadIdentifier</key>
    > =A0 =A0 =A0<string>com.domain.enterprise.eas</string>
    > =A0 =A0 =A0<key>PayloadOrganization</key>
    > =A0 =A0 =A0<string>TipsHouse</string>
    > =A0 =A0 =A0<key>PayloadType</key>
    > =A0 =A0 =A0<string>com.apple.eas.account</string>
    > =A0 =A0 =A0<key>PayloadUUID</key>
    > =A0 =A0 =A0<string>FE477C13-BF4F-4EA0-BE09-3968EC40C952</string>
    > =A0 =A0 =A0<key>PayloadVersion</key>
    > =A0 =A0 =A0<integer>1</integer>
    > =A0 =A0 =A0<key>SSL</key>
    > =A0 =A0 =A0<true/>
    > =A0 =A0 =A0<key>UserName</key>
    > =A0 =A0 =A0<string>domain\{userroot}</string>
    > =A0 =A0</dict>
    > =A0</array>
    > =A0<key>PayloadDescription</key>
    > =A0<string>Profile Test</string>
    > =A0<key>PayloadDisplayName</key>
    > =A0<string>TipsHouse</string>
    > =A0<key>PayloadIdentifier</key>
    > =A0<string>com.domain.enterprise</string>
    > =A0<key>PayloadOrganization</key>
    > =A0<string>Domain</string>
    > =A0<key>PayloadRemovalDisallowed</key>
    > =A0<false/>
    > =A0<key>PayloadType</key>
    > =A0<string>Configuration</string>
    > =A0<key>PayloadUUID</key>
    > =A0<string>A6B7D66D-1179-4E85-A005-4DAACD4EDF0F</string>
    > =A0<key>PayloadVersion</key>
    > =A0<integer>1</integer>
    > </dict>
    > </plist>
    >
    > And the outbound replaces elements in only the array area (in this case,
    > just the EAS but other options may be included - LDAP, IMAP, etc.)
    > <dict>
    > =A0 =A0 =A0<key>EmailAddress</key>
    > =A0 =A0 =A0<string></string>
    > =A0 =A0 =A0<key>Host</key>
    > =A0 =A0 =A0<string>exchange.domain.com</string>
    > =A0 =A0 =A0<key>MailNumberOfPastDaysToSync</key>
    > =A0 =A0 =A0<integer>3</integer>
    > =A0 =A0 =A0<key>Password</key>
    > =A0 =A0 =A0<string>MyPassword</string>
    > =A0 =A0 =A0<key>PayloadDescription</key>
    > =A0 =A0 =A0<string>Configures device for use with Microsoft Exchange
    > ActiveSync services.</string>
    > =A0 =A0 =A0<key>PayloadDisplayName</key>
    > =A0 =A0 =A0<string>Exchange</string>
    > =A0 =A0 =A0<key>PayloadIdentifier</key>
    > =A0 =A0 =A0<string>com.domain.enterprise.eas</string>
    > =A0 =A0 =A0<key>PayloadOrganization</key>
    > =A0 =A0 =A0<string>TipsHouse</string>
    > =A0 =A0 =A0<key>PayloadType</key>
    > =A0 =A0 =A0<string>com.apple.eas.account</string>
    > =A0 =A0 =A0<key>PayloadUUID</key>
    > =A0 =A0 =A0<string>FE477C13-BF4F-4EA0-BE09-3968EC40C952</string>
    > =A0 =A0 =A0<key>PayloadVersion</key>
    > =A0 =A0 =A0<integer>1</integer>
    > =A0 =A0 =A0<key>SSL</key>
    > =A0 =A0 =A0<true/>
    > =A0 =A0 =A0<key>UserName</key>
    > =A0 =A0 =A0<string>domain\greghacke</string>
    > =A0 =A0</dict>
    >
    > Now, the initial file is provided to me may be replaced as needed. I
    > would like to avoid converting it to ERb as I cannot gaurentee anyone
    > else will do the work to ensure it stays updated and correct.
    >
    > I've dug around - really - and found two examples for single element
    > replacement.
    >
    > My belief is that there are a plethora of options execute this. I would
    > like to do something like:
    > File.copy(master,user_file)
    > File.open('/tmp/temp_file.txt', 'w+') do | new_file |
    > =A0 =A0 new_file.puts(File.open(user_file, 'r') do | original_file |
    > =A0 =A0 original_file.read.gsub(/\{username\}/, username)
    > =A0 =A0 end)
    > end
    > FileUtils.mv("/tmp/replaceable2.txt", user_file)
    >
    > =A0text=3D File.read user_file
    > =A0File.open(user_file, 'w+'){|f| f << text.gsub(/\{username\}/,
    > username)}


    You can use the block form of gsub to do only one pass:

    variables =3D {"username" =3D> "Bob", "password" =3D> "pwd"}

    file_contents =3D File.read("master_file").read
    file_contents.gsub!(/\{(.*?)\}/) {|m| variables[$1]}

    #and then write the file contents to another file, delete and rename

    Jesus.
     
    Jesús Gabriel y Galán, May 11, 2011
    #9
  10. Greg Hacke

    7stud -- Guest

    You can also read the file line by line, and use a hash of replacements
    with gsub:

    replacements = {
    '{username}' => 'BOB',
    '{password}' => 'BOB-PASSWORD',
    '{userroot}' => 'BOB-USERROOT'
    }

    pattern = '{.*?}'

    File.open('out.xml') do |outfile|
    IO.foreach('in.xml') do |line|
    outfile.print gsub(/#{pattern}/, replacements)
    end
    end

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, May 12, 2011
    #10
  11. Greg Hacke

    7stud -- Guest

    And here is a xml parsing solution:

    require 'rexml/document'
    include REXML

    xml =<<ENDOFXML
    #your xml here
    ENDOFXML

    replacements = {
    '{username}' => 'BOB',
    '{password}' => 'BOB-PASSWORD',
    '{userroot}' => 'BOB-USERROOT'
    }

    pattern = '{.*?}'
    doc = REXML::Document.new(xml)

    XPath.each(doc, '//string') do |element|
    text = element.text
    element.text = text.gsub(/#{pattern}/, replacements)
    end

    puts doc.to_s


    Note that you are using an unfortunate character in the string:

    domain\{userroot}

    A backslash has a special meaning in ruby strings. You need to change
    that to a forward slash(or escape it).

    --
    Posted via http://www.ruby-forum.com/.
     
    7stud --, May 12, 2011
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kurt Euler
    Replies:
    3
    Views:
    98
    Mauricio Fernández
    Sep 4, 2003
  2. James R. Leu

    gsub with match replacement

    James R. Leu, Feb 3, 2004, in forum: Ruby
    Replies:
    1
    Views:
    131
    Carlos
    Feb 3, 2004
  3. aurelianito

    gsub and gsub! are inconsistent

    aurelianito, Nov 8, 2005, in forum: Ruby
    Replies:
    9
    Views:
    179
    Robert Klemme
    Nov 9, 2005
  4. ridcully
    Replies:
    4
    Views:
    134
  5. Shea Barton

    Partial GSUB match / replacement

    Shea Barton, Nov 20, 2010, in forum: Ruby
    Replies:
    6
    Views:
    128
    Shea Barton
    Nov 21, 2010
Loading...

Share This Page