How replace variable values in many text based files
I need a script/program/whatever to replace specific variable values in many text based files. I was thinking that regular expression was the keyword, but not so much in to that...
More precise description of the problem:
Original code in a file:
POTATO = -3000;
POTATO = 1020; !this value is updated 2011-08-28
Code after "conversion" (5000 added to the variable):
POTATO = 2000;
POTATO = 6020; !this value is updated 2011-08-28
Above is just an down scaled example as the variable POTATO has many diffrent values in many different files...
Please advise! Mikkel
Hi All, Thanx alot for all your posts that lead me to this result that seems to work briliant:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
class test
{
static void Main()
{
ShowOutput("T开发者_开发技巧OMATO =-2000");
ShowOutput("POTATO =-2000");
ShowOutput("POTATOO = 5000");
ShowOutput("TOMATO =-2000");
ShowOutput("POTATO = -2000 'This is a nice value");
ShowOutput("POTATO =-2000 'This is also a nice value");
}
public static void ShowOutput(string InputStreng)
{
Console.WriteLine("BEFORE: " + InputStreng);
Console.WriteLine("AFTER: " + IncrementValues(InputStreng, 1));
Console.WriteLine();
Console.ReadLine();
}
private static string IncrementValues(string input, int increment)
{
string pattern = @"(?<=POTATO =\s*)(-?\d+)";
var regex = new System.Text.RegularExpressions.Regex(pattern,
System.Text.RegularExpressions.RegexOptions.Multiline);
return regex.Replace(input, delegate(Match match)
{
long value = Convert.ToInt64(match.Groups[1].Value);
return (value + 5000).ToString();
});
}
}
Now I just need to figure out the hard part - making above code work on textfile.. :)
Cheers! Mikkel
you can use notepad++ "find in files" feature (ctrl h)
you can search for the text POTATO = -3000; POTATO = 1020; !this value is updated 2011-08-28
choose the dircetory that has all the files and check "in all sub folders"
and replace with (5000 added to the variable): POTATO = 2000; POTATO = 6020; !this value is updated 2011-08-28
You can do it like this:
var re = new Regex(@"(?<=^POTATO = )-?\d+(?=;)", RegexOptions.Multiline);
var result = re.Replace(s, m => (int.Parse(m.Value) + 5000).ToString());
This creates a regex that matches optional minus (-?
) followed by one or more decimal digits (\d+
), but only when it is preceded by the string POTATO =
((?<=^POTATO = )
) and followed by a semicolon (?=;)
. Then it uses lambda to convert the matched value to int
, add 5000 to it and convert it back to string
.
Using Regular Expression is your key here, Use the Matchevaluator
delegate to convert every match to int
or long
, and then add your conversion
to that string:
private sting IncrementValues(string input, int increment)
{
//assuming your input is: POTATO = -3000;
// POTATO = 1020; !this value is updated 2011-08-28";
string pattern = @"(?<=(^|\s)POTATO = )(-?\d+)(?=;)";
var regex = new System.Text.RegularExpressions.Regex(pattern,
System.Text.RegularExpressions.RegexOptions.Multiline);
return regex.Replace(input, delegate(Match match)
{
long value = Convert.ToInt64(match.Groups[1].Value);
return (value + 5000).ToString();
});
}
result will be:
POTATO = 2000;
POTATO = 6020; !this value is updated 2011-08-28
Edit: I updated the pattern of search, thanks to @svick to point out a bug in the pattern that was causing the results to swallow spaces after the =
sign, it was prints POTATO =2000;
instead of POTATO = 2000;
RegEx is a good solution for this type of problem. Thought I'd toss in an alternative that uses recursion and strings if you have RegExPhobia.
There are a few assumptions here such as the string preceding the integer to update will always be in the same format of xxxx<space>=<space>value;
. And the value after the variable name is always an integer followed by a semi-colon. If this is not always the case, then the method can be tweaked to accommodate those types scenarios.
private void SomeMethod( ... )
{
string str = GetTextFile( ... ); // read text file into a string
// 2nd param should include the space before and after the = sign.
string updated = UpdateValue( str, "potato = ", 5000, 0 );
UpdateTextFile( ... ); // update the original text file
}
/// <summary>
/// Updates the value of all integer values in a string that
/// are preceeded by the string to <param name="match"></param>.
/// Uses recursion to update all values.
/// </summary>
/// <param name="original">Entire original string.</param>
/// <param name="match">Phrase preceeding the value to update.</param>
/// <param name="increaseBy">Amount to increase the variable by.</param>
/// <param name="startIndex">Index of the original string to start looking
/// for the <param name="match"></param> phrase. Index should always
/// be 0 when calling method for first time. <param name="startIndex"></param>
/// will be updated automatically through recursion.
/// </param>
private static string UpdateValue( string original, string match, int increaseBy, int startIndex )
{
string skip = original.Substring( 0, startIndex );
string fragment = original.Substring( startIndex );
int start = fragment.IndexOf( match, StringComparison.OrdinalIgnoreCase );
if( start == -1 )
{
return original;
}
start = start + match.Length;
int end = fragment.IndexOf( ";", start );
if( end == -1 )
{
return original;
}
string left = fragment.Substring( 0, start );
string right = fragment.Substring( end );
string value = fragment.Substring( start, end - start );
int newValue = int.Parse( value ) + increaseBy;
string str = skip + left + newValue + right;
return UpdateValue( str, match, increaseBy, startIndex + end );
}
精彩评论