2

I am new to ruby and writing the expression to replace the string between the xml tags by hashing the value inside that.

I did the following to replace with the new password

puts "<password>check1</password>".gsub(/(?<=password\>)[^\/]+(?=\<\/password)/,'New \0')
RESULT: <password>New check1</password> (EXPECTED)

My expectation is to get the result like this (Md5 checksum of the value "New check1")

<password>6aaf125b14c97b307c85fc6e681c410e</password>

I tried it in the following ways and none of them was successful (I have included the required libraries "require 'digest'").

puts "<password>check1</password>".gsub(/(?<=password\>)[^\/]+(?=\<\/password)/,Digest::MD5.hexdigest('\0'))
puts "<password>check1</password>".gsub(/(?<=password\>)[^\/]+(?=\<\/password)/,Digest::MD5.hexdigest '\0')
puts "<password>check1</password>".gsub(/(?<=password\>)[^\/]+(?=\<\/password)/, "Digest::MD5.hexdigest \0")

Any help on this to achieve the expectation is very much appreciated

Aravindhan
  • 3,566
  • 7
  • 26
  • 42
  • 1
    This is the obligatory comment that you should probably be using a proper XML parser instead of regex e.g. Nokogiri. – Max Jun 20 '18 at 15:56
  • 4
    Or to be more specific, obligatory: [**TH̘Ë͖́̉ ͠P̯͍̭O̚​N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬC̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ**](https://stackoverflow.com/a/1732454/1954610). Regex is fine for a "quick and dirty" solution, but in general it is *not* the right way to do handle XML. (What if the password contains a `<` character? What if that portion of xml is commented out? What if there's an attribute on the field, like ``? What if there's a blank password attribute, like `` or ``? ... And so on.) – Tom Lord Jun 20 '18 at 16:24

2 Answers2

2

This will work:

require 'digest'

line = "<other>stuff</other><password>check1</password><more>more</more>"

line.sub(/<password>(?<pwd>[^<]+)<\/password>/, Digest::SHA2.hexdigest(pwd))

 => "<other>stuff</other>8a859fd2a56cc37285bc3e307ef0d9fc1d2ec054ea3c7d0ec0ff547cbfacf8dd<more>more</more>"

Make sure the input is one line at a time, and you'll probably want sub, not gsub

P.S.: agree with Tom Lord's comment.. if your XML is not gargantuan in size, try to use an XML library to parse it... Ox or Nokogiri perhaps? Different libraries have different advantages.

Tilo
  • 33,354
  • 5
  • 79
  • 106
0

This is a variant of Tilo's answer.

require 'digest'

line = "<other>stuff</other><password>check1</password><more>more</more>"

r = /(?<=<password>).+?(?=<\/password>)/

line.sub(r) { |pwd| Digest::SHA2.hexdigest(pwd) }
   #=> "<other>stuff</other><password>8a859fd2a56cc37285bc3e307ef0d9f
   #    c1d2ec054ea3c7d0ec0ff547cbfacf8dd</password><more>more</more>"

(I've displayed the returned string on two lines so make it readable without the need for horizontal scrolling.)

The regular expression reads, "match '<password>' in a positive lookbehind ((?<=...)), followed by any number of characters, lazily ('?'), followed by the string '</password>' in a positive lookahead ((?=...)).

Rob
  • 26,989
  • 16
  • 82
  • 98
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100