I have this line of code that I'm using to prepare some CSS file:
TheMinifiedCSS = TheMinifiedCSS.Replace("white", "#FFF");
The problem is that in CSS, I have this declaration:
.SomeClass{white-space:pre-wrap;}
How do I change the .Replace
statement to replace white
with #FFF
but to leave white-space
alone?
Thanks.
Note, I know I can add TheMinifiedCSS = TheMinifiedCSS.Replace("#FFF-space", "white-space");
but I'm looking for something cleaner.
People keep trying to write rules for things that appear before or after "white"
, when I think what's desired is that "white"
is its own token and not part of a selector.
Regex.Replace(TheMinifiedCSS, @"(?<![-_a-zA-Z0-9#.])white(?![-_a-zA-Z0-9])", @"#FFF");
A more complete rule would implement the entire rule for identifier tokens in CSS, but I think this one covers all keywords.
Here's a slightly trickier test case than has been posted so far:
.white> TD { color: white;box-shadow: 0px 0px 3px white, inset 0px 0px 5px black; white-space:pre-wrap; }
BODY { background: url('test.png'),white; }
Even trickier, and not handled by my example, are filenames.
BODY
{
background-color:white;
background-image:url('almost white, but not really.png');
}
To get that right, you probably need a full CSS parser.
You can use regular expression for it. I think this is the best way for you. Here is the link where you can get more detailed information:
http://msdn.microsoft.com/en-us/library/xwewhkd1.aspx
I am not really strong with building patterns for regular expressions, but you can try this sample
static void Main(string[] args)
{
var inputText = @"white-space: 0; color: white;
box-shadow: 10px 20px 30px white, inset 0px 0px 5px black;";
inputText = ChangeColor(inputText, "white", "#FFF");
}
private static string ChangeColor(string css, string oldColor, string newColor)
{
// Rule 1
var pattern1 = string.Format(@"(color)(\s*):(\s*){0}(\s*)", oldColor);
var replacement = string.Format("$1 : {0}", newColor);
var rgx = new Regex(pattern1);
css = rgx.Replace(css, replacement);
// Rule 2
var pattern2 = string.Format(@"([\d]*)px(\s*)([\d]*)px(\s*)([\d]*)px(\s*){0}", oldColor);
var replacement2 = string.Format("$1px $3px $5px {0}", newColor);
rgx = new Regex(pattern2);
css = rgx.Replace(css, replacement2);
return css;
}
Regex can make things a lot more complicated. Here is a solution that works. Has solution for comments and strings as well.
static void Main(string[] args)
{
string test = ".white> TD { color: white;box-shadow: 0px 0px 3px white, inset 0px 0px 5px black; white-space:pre-wrap; background-image='white black \" white \"'}";
Console.WriteLine("Before: " + test);
test = replaceInCSS(test, "white", "green");
Console.WriteLine("After: " + test);
Console.ReadLine();
}
static string replaceInCSS(string text, string replace, string replacement)
{
char[] forceBefore = new char[]{ '\n', '\t', ';', '{', ' ', ':', ','};
char[] forceAfter = new char[] { ';', '}', ' ', ','};
int index = text.IndexOf(replace, 0);
while (index != -1)
{
if (!indexWithinStringOrComment(text, index))
{
int afterPos = index + replace.Length;
bool beforeOk = false, afterOk = false;
if (index > 0 && forceBefore.Contains<char>(text[index - 1]))
beforeOk = true;
if (afterPos < text.Length - 1 && forceAfter.Contains<char>(text[afterPos]))
afterOk = true;
if ((index == 0 || beforeOk) &&
(afterPos == text.Length - 1 || afterOk))
{
text = text.Remove(index, replace.Length);
text = text.Insert(index, replacement);
}
}
index = text.IndexOf(replace, index + 1);
}
return text;
}
static bool indexWithinStringOrComment(string text, int index)
{
bool insideStrSimple = false;
bool insideStrDouble = false;
bool insideStrComment = false;
for (int i = 0; i < index; ++i)
{
string subStr = text.Substring(i, 2);
if (text[i] == '\'' && !insideStrDouble && !insideStrComment)
insideStrSimple = !insideStrSimple;
else if (text[i] == '"' && !insideStrSimple && !insideStrComment)
insideStrDouble = !insideStrDouble;
else if (text.Substring(i, 2) == "/*" && !insideStrDouble && !insideStrSimple)
insideStrComment = true;
else if (text.Substring(i, 2) == "*/" && insideStrComment)
insideStrComment = false;
}
return insideStrDouble || insideStrSimple || insideStrComment;
}
Output:
Before: .white> TD { color: white;box-shadow: 0px 0px 3px white, inset 0px 0px 5px black; white-space:pre-wrap; background-image='white black \" white \"'}
After: .white> TD { color: green;box-shadow: 0px 0px 3px green, inset 0px 0px 5px black; white-space:pre-wrap; background-image='white black \" white \"'}
Edit: There we go. Inside string problem is also solved. This should work to replace any css property. Edit again: Added fix for comments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With