0

I have an xml file that i need to find, multiply (e.g. by 1.25) and replace all prices.

Price tag looks like that: <price><![CDATA[15.9]]></price>

The price tag should look like that after the operation: <price><![CDATA[19.875]]></price>

Can this be done in Notepad++ or PowerGrep using a regular expression?

Thanks in advance.

Sophocles
  • 1
  • 3
  • 1
    Regular expressions can't multiply numbers. But you can write a tiny program that uses regexp to find all prices, multiply and replace it. – trailmax Sep 10 '14 at 13:08

2 Answers2

0

As far as I know you can't use either program to preform the math but you can build a simple program in most any language of your choice to take a file use regex to find the number. Cast that string as a double do the math and put it back into the string. Later on today I could probably build something in c# but it should be relatively straight forward in most languages. You may even be able to build a shell script and use grep if you're not in a windows environment or use Powershell for windows but I have less experience with Powershell.

Edit: There is an easier way to do this http://msdn.microsoft.com/en-us/library/hcebdtae(v=vs.110).aspx this is essentially what you want to do using the xmldocument object.

Edit2: I did this even though I couldn't get a hold of the original poster I thought someone might be able to use the info and I learned a lot. I can add the source code to github if anyone is interested.

public static void ChangePricesWork(string filepath, double multiply)
{
  var document = new XmlDocument();
  document.Load(filepath);
  XmlNodeList nodeList = document.GetElementsByTagName("price");

  foreach (XmlNode node in nodeList)
  {
      if (!string.IsNullOrEmpty(node.InnerText))
      {
         node.InnerText = Convert.ToString(multiplyPrice(multiply, node.InnerText));
      }

   }

   string newFilePath = string.Format(@"{0}\{1}_updated.xml", Path.GetDirectoryName(filepath),   Path.GetFileNameWithoutExtension(filepath)); 
   document.Save(newFilePath);
}

   private static double multiplyPrice(double multiply, string oldPrice)
   {
     var newPrice = new double();
     if (Double.TryParse(oldPrice, out newPrice))
     {
       newPrice = newPrice * multiply;
     }
     return newPrice;
   }
thekidxp
  • 1
  • 1
  • 1
  • Thank you both, for saving my time (that would be spend in searching). For programmers like you it might be an easy thing but for "users" like me it's a mountain. If (and only if) it's no big thing, i would like to see the solution you say. Best regards to all. – Sophocles Sep 11 '14 at 04:55
  • How many files do you need to check and how much is the multiplication by? Is it the same every time? If I get a little more info I'll definitely do this for you it shouldn't take me too long I'll just have to take care of it when I'm not at work. – thekidxp Sep 11 '14 at 13:10
  • It's only one file (xml product catalog) and the price needs to be multiplied by 1.05 (5% margin). – Sophocles Sep 11 '14 at 14:40
  • The comments are getting a little specific and off topic of the problem so if you want to email me at my email which should be in my profile I have a couple of final questions I almost got this finished over lunch and I'll post the source code here or on git hub so others can benefit later. – thekidxp Sep 11 '14 at 19:09
  • Thanks both of you. Now that someone has started the engine, i'm sure that i'll figure it out. Best regards (kidpx, i couldn't find any email address) – Sophocles Sep 13 '14 at 04:44
0

Notepad++ has a Pythonscript plugin that allows you to create quick Python scripts that have access to your document and Notepad++ itself.

The install and setup is described in this answer.

The API has moved on a little bit since then, you do a regular expression replace with Editor.rereplace now.

# Start a sequence of actions that is undone and redone as a unit. May be nested.
editor.beginUndoAction()

# multiply_price_cdata
from decimal import *
TWOPLACES = Decimal(10) ** -2 

def multiply_price_cdata( m ):
    price = Decimal( m.group(2) ) * Decimal( 1.25 )
    return  m.group(1) + str(price.quantize(TWOPLACES)) + m.group(3)

def cdata( m ):
    return "CDATA"

# npp++ search/replace
re_price = r'(<price><!\[CDATA\[)(\d+\.\d+|\d+)(\]\]></price>)'
editor.rereplace( re_price , multiply_price_cdata )

# end the undo sequence
editor.endUndoAction()
Community
  • 1
  • 1
Matt
  • 68,711
  • 7
  • 155
  • 158
  • The script works fine when the price has decimal value, e.g. "15.25", but it does not affect the price when it doesn;t have a decimal value e.g. "15". Is there a way to multiply both types? – Sophocles Jan 03 '15 at 08:21
  • Yes, you could specify an optional match of a regex with a `?` or add a logical OR with a pipe `|`. I have updated the answer to match both types. You could also be specific to two decimal places with \d{2} – Matt Jan 03 '15 at 14:31
  • Thanx; it seems to be just fine. – Sophocles Jan 04 '15 at 10:06