0

My program parses an XML-File which contains paths. Now I need to parse special folders like Appdata on different Windows devices:

<entry path="C:\Users\Simon\AppData\Roaming\myprogram" />

My attempt is to change the line into:

<entry path="#{APPDATA}\myprogram" />

and parse it using a Regular Expression:

string pattern = "#{ * }"; // what does fit here?

I've read some tutorials one Regex but I just can't figure out which Regex fits here.

How can I get the content between #{ and } using a regular Expression?

2
  • 4
    Why do you need regexp? If you have map of special paths that you want to change, simply string.Replace would do the job Commented Oct 6, 2015 at 14:23
  • 1
    @IgorisAzanovas And i wouldn't do this with a string containing the whole XML. Use the XMLDocument - Object to get the entry and modify it's "path" property. Commented Oct 6, 2015 at 14:26

4 Answers 4

2

Just register general placeholders which you replace, e.g.

Dictionary<string, string> placeholders = new Dictionary<string, string>
{
    { "#{APPDATA}", @"C:\Users\Simon\AppData\Roaming" },
    { "#{SYSTEM32}", @"C:\Windows\System32" }
};

string ReplacePlaceholders (string text)
{
    foreach (var kv in placeholders)
    {
        text = text.Replace(kv.Key, kv.Value);
    }
    return text;
}

Used like this:

// this would come from the XML attribute
string path = @"#{APPDATA}\myprogram";

string newPath = ReplacePlaceholders(path);
Console.WriteLine(newPath); // C:\Users\Simon\AppData\Roaming\myprogram

As for actual values paths, you can also use Environment.GetFolderPath with the Environment.SpecialFolder enumeration to get the actual paths. But for the replacements and also other values, the answer still applies

Finally, since I wasn’t sure from your question in what direction you wanted to make these replacements, of course you can also reverse the mapping in above dictionary. I just assumed you had placeholders you wanted to replace by real paths.

Sign up to request clarification or add additional context in comments.

1 Comment

Environment.SpecialFolder?
1

You would want to use a match group in your regex. It would look like:

"#{(.*)}"

Then the Match.Groups property (documentation in the above link) would contain that "APPDATA" text.


This code prints "APPDATA" to the console

        var matches = Regex.Matches(@"#{APPDATA}\myprogram", "#{(.*)}");
        foreach (Match match in matches)
          Console.WriteLine(match.Groups[1].Value);

3 Comments

For the record, I think @poke has a better solution to the overall problem, but I went for an answer to the specific question of getting the text from a match in regex. If I was implementing this behavior I would use poke's solution.
@poke actually yes it is a valid regex. what is invalid about it? (unless you are talking about the surrounding quotes? The OP had it in a string assigned to a variable so I left the quotes in there)
Odd, I was thinking that the unescaped curly braces (a quantifier in regexes) would break but apparently, C#’s implementation is smart enough not to parse them as quantifiers when they don’t contain a number range. Nevermind me then :)
1

Reading your question once again, maybe it is the other way you are asking?

void Main()
{
  string myXML = @"
  <x>
  <paths>
  <entry path=""#{APPDATA}\myprogram"" />
  <entry path=""#{APPDATA}\yourprogram"" />
  <entry path=""#{APPDATA}\hisprogram"" />
  <entry path=""C:\OtherFolder\DummyProgram"" />
  <entry src=""C:\OtherFolder\DummyProgram"" />
  </paths>
  <Other>Other</Other>
  </x>";

  var appdata = Environment.GetFolderPath( 
    Environment.SpecialFolder.ApplicationData );
XDocument doc = XDocument.Parse(myXML);

  doc.Descendants("entry")
  .Where(xd => xd.Attribute("path") != null &&
      ((string)xd.Attribute("path")).StartsWith("#{APPDATA}"))
  .ToList()
  .ForEach(e => {
     var oldPath = (string)e.Attribute("path");
     var newPath = Path.Combine(appdata, Path.GetFileName(oldPath));
     e.Attribute("path").SetValue(newPath);
     } );

  Console.WriteLine( doc.ToString() );

}

Comments

0

Wouldn't it be simpler to use Linq To XML for this. I couldn't see an exact pattern in your question, but probably something like this:

void Main()
{
  string myXML = @"
  <x>
  <paths>
  <entry path=""C:\Users\Simon\AppData\Roaming\myprogram"" />
  <entry path=""C:\Users\Simon\AppData\Roaming\yourprogram"" />
  <entry path=""C:\Users\Simon\AppData\Roaming\hisprogram"" />
  <entry path=""C:\OtherFolder\DummyProgram"" />
  <entry src=""C:\OtherFolder\DummyProgram"" />
  </paths>
  <Other>Other</Other>
  </x>";

XDocument doc = XDocument.Parse(myXML);

  doc.Descendants("entry")
  .Where(xd => xd.Attribute("path") != null &&
      ((string)xd.Attribute("path")).ToLower().Contains("appdata"))
  .ToList()
  .ForEach(e => {
     var oldPath = (string)e.Attribute("path");
     var newPath = @"#{APPDATA}\" + Path.GetFileName(oldPath);
     e.Attribute("path").SetValue(newPath);
     } );

  Console.WriteLine( doc.ToString() );

}

4 Comments

What if my user name was appdata?
What does it matter? It would get replaced.
My point was mostly, that a path C:\Users\appdata\Documents\foo\bar\baz would be—incorreclty—replaced to #{APPDATA}\baz too.
I don't think it would be incorrect. I don't see in original question that states he already does know the path. He says if there is "appdata" in path. Maybe I should just make that \appdata\ instead of just appdata. It would be "correctly" replaced IMHO.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.