A few hints that should get you started:
Assume that your string processor function is called ProcessStrings.
1) Include Constants.cs into the same project as the ProcessStrings function, so it gets compiled in with the refactoring code.
2) Reflect over your Constants class to build a Dictionary of language strings to constant names, something like:
Dictionary<String, String> constantList = new Dictionary<String, String>();
FieldInfo[] fields = typeof(Constants).GetFields(BindingFlags.Static | BindingFlags.Public);
String constantValue;
foreach (FieldInfo field in fields)
{
if (field.FieldType == typeof(String))
{
constantValue = (string)field.GetValue(null);
constantList.Add(constantValue, field.Name);
}
}
3) constantList should now contain the full list of Constant names, indexed by the string they represent.
4) Grab all the lines from the file (using File.ReadAllLines).
5) Now iterate over the lines. Something like the following should allow you to ignore lines that you shouldn't be processing.
//check if the line is a comment or xml comment
if (Regex.IsMatch(lines[idx], @"^\s*//"))
continue;
//check if the entry is an attribute
if (Regex.IsMatch(lines[idx], @"^\s*\["))
continue;
//check if the line is part of a block comment (assuming a * at the start of the line)
if (Regex.IsMatch(lines[idx], @"^\s*(/\*+|\*+)"))
continue;
//check if the line has been marked as ignored
//(this is something handy I use to mark a string to be ignored for any reason, just put //IgnoreString at the end of the line)
if (Regex.IsMatch(lines[idx], @"//\s*IgnoreString\s*$"))
continue;
6) Now, match any quoted strings on the line, then go through each match and check it for a few conditions. You can remove some of these conditions if needs be.
MatchCollection mC = Regex.Matches(lines[idx], "@?\"([^\"]+)\"");
foreach (Match m in mC)
{
if (
// Detect format insertion markers that are on their own and ignore them,
!Regex.IsMatch(m.Value, @"""\s*\{\d(:\d+)?\}\s*""") &&
//or check for strings of single character length that are not proper characters (-, /, etc)
!Regex.IsMatch(m.Value, @"""\s*\\?[^\w]\s*""") &&
//check for digit only strings, allowing for decimal places and an optional percentage or multiplier indicator
!Regex.IsMatch(m.Value, @"""[\d.]+[%|x]?""") &&
//check for array indexers
!(m.Index <= lines[idx].Length && lines[idx][m.Index - 1] == '[' && lines[idx][m.Index + m.Length] == ']') &&
)
{
String toCheck = m.Groups[1].Value;
//look up the string we found in our list of constants
if (constantList.ContainsKey(toCheck))
{
String replaceString;
replaceString = "Constants." + constants[toCheck];
//replace the line in the file
lines[idx] = lines[idx].Replace("\"" + m.Groups[1].Value + "\"", replaceString);
}
else
{
//See Point 8....
}
}
7) Now join the array of lines back up, and write it back to the file. That should get you most of the way.
8) To get it to generate constants for strings you don't already have an entry for, in the else block for looking up the string,
generate a name for the constant from the string (I just removed all special characters and spaces from the string and limited it to 10 words). Then use that name and the original string (from the toCheck variable in point 6) to make a constant declaration and insert it into Constants.cs.
Then when you run the function again, those new constants will be used.