3

I would like to replace certain text throughout an SVG file using regex.

For example, I might have many attributes like the following in the file:

<g clip-path="url(#clipId0)" fill="none" stroke="rgb(150,150,150)" stroke-opacity="0.14902" stroke-width="0.425" >
<polyline points="17001.1,7859.91 17018.7,7859.91 17018.7,7901.08 17001.1,7901.08 17001.1,7859.91 " />
<polyline points="17018.7,7880.5 17001.1,7880.5 " />
<polyline points="17018.7,7883.44 17001.1,7883.44 " />
</g>

and I would like to replace

stroke="rgb(150,150,150)"

to be

stroke="rgb(100,100,100)"

Note that the original numerical values will likely be different at each instance, but I want to change them all to (100,100,100)

I tried the following:

        //Make SVG monochrome
        string svgText = File.ReadAllText(svgPath);
        Regex.Replace(svgText, "stroke=\"rgb(.*,.*,.*)\"", "stroke=\"rgb(100,100,100)\"");
        File.WriteAllText(svgPath, svgText);

But of course, it did not work, because of the parenthesis. When I use an escape before the parens '\(' and '\)', I get the red squiggle error indicating an unrecognized escape character, but for regular expressions, I should escape parenthesis characters so that they are taken literally since they are special characters for regex. Correct?

How should I use regular expressions in this string to achieve what I want?

E. A. Bagby
  • 824
  • 9
  • 24
  • 4
    Why would you do that instead of using an XML parser that already exists? – rory.ap May 23 '18 at 19:56
  • 4
    As great and powerful as regexes are, a built in parser will fix it all up for you :) – sniperd May 23 '18 at 19:57
  • 1
    Actually, I haven't tried parsing svg attributes with an XML parser. The attributes are more complex than I'm used to. Any examples. I actually looked and didn't find one. – E. A. Bagby May 23 '18 at 20:00
  • 2
    Look in the System.Xml namespace. I usually use the XmlDocument class. You can query nodes with XPath. – rory.ap May 23 '18 at 20:01
  • 2
    You'll need to escape the backslashes to stop them from being interpreted as the start of an escape sequence. eg. `"stroke=\"rgb\\(.*,.*,.*\\)\""`. Alternately, you should be able to use a verbatim string literal, as discussed here: https://stackoverflow.com/questions/556133/whats-the-in-front-of-a-string-in-c – Zak May 23 '18 at 20:03
  • 1
    Can I manipulate the stroke with the XML parser easily without worrying about the entity type? Stroke can be part of a variety of entity types from what understand circles, blocks, lines, polylines? If not, that's why I was looking at doing a simple find replace. – E. A. Bagby May 23 '18 at 20:04
  • 3
    You are looking for something like `svgText = Regex.Replace(svgText, @"stroke=""rgb\(\d{1,3},\d{1,3},\d{1,3}\)""", "stroke=\"rgb(100,100,100)\"");`, but really - use xml parser instead. – Evk May 23 '18 at 20:05
  • 1
    Evik--just an FYI, the number could be one or two characters. 0 or 50 or 255 for example. – E. A. Bagby May 23 '18 at 20:06
  • 3
    @EdwardBagby that's what is used in regex above. `\d{1,3}` means "1-3 digits". – Evk May 23 '18 at 20:08
  • 1
    Ah, cheers. Worked beautifully Evik. and of couse I made the mistake not to place the modified string back into the variable. I'll look into using the XML parser. Just need to get this working asap. Thanks all. – E. A. Bagby May 23 '18 at 20:10

1 Answers1

2

While not being a C# developer, I would still guess that this works for your regex string:

@"stroke=""rgb\(\d+,\d+,\d+\)"""

Don't use .*, as it will match 0 or more of (almost) any character.

\d will match a digit (generally just 0-9, but it can also match various non-Arabic digits in some regex dialects.)

Happy coding!

Zak
  • 1,042
  • 6
  • 12