David Ruttka

I make computers do things

MSBuild String Manipulation Chaos

The other day, I was trying to split a string and then get the various parts of it from within an MSBuild project, but it went totally nuts on me. When I tried to access the item at a given index of the split result, I’d get nonsense including semicolons that weren’t there in the first place! Why are semicolons suddenly appearing in the result of a String Split when there were none in the original string?

Once I realized I should take this to the command line and break it down, it made a lot more sense and was quickly resolved (isn’t that usually the case?). I’m posting this so that maybe someone else will find it useful later.

The Goal

Imagine that you have a property that you want to split, and then rejoin all or some of the parts later. A build number seems like a good general example here. You’ve got access to String.Split here, so it seems a natural solution.

1
2
3
4
5
6
7
8
9
10
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Split>$(BuildNumber.Split('.'))</Split>
  </PropertyGroup>

  <Target Name="Dump">
    <Message text="$(BuildNumber)" />
    <Message text="$(Split[0]).$(Split[1]).$(Split[2]).$(Split[3])" />
  </Target>
</Project>

I expected Split[0] to be 8, Split[1] to be 67, etc. What really happened was:

1
2
3
Dump:
8.67.5309.9001
8.;.6.7

Huh?

Where did that semicolon come from, and why do I get 6 and 7 instead of 67? I’ll admit I hacked and searched on this for way too long before turning to the old standby of “echo something out,” but once I did…

1
2
3
4
5
6
7
8
9
10
11
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Split>$(BuildNumber.Split('.'))</Split>
  </PropertyGroup>

  <Target Name="Dump">
    <Message text="$(BuildNumber)" />
    <Message text="$(Split)" />
  </Target>
</Project>

I got some very informative output…

1
2
3
Dump:
8.67.5309.9001
8;67;5309;9001

The Property Is A String

What is happening here is that the property that I’m creating is a string, not an array. It gets rejoined automatically, with semicolons as the delimiters. What I ended up doing was immediately capturing the chunks as separate properties.

1
2
3
4
5
6
7
8
9
10
11
12
13
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <BuildNumber>8.67.5309.9001</BuildNumber>
    <Major>$(BuildNumber.Split('.')[0])</Major>
    <Minor>$(BuildNumber.Split('.')[1])</Minor>
    <Build>$(BuildNumber.Split('.')[2])</Build>
    <PowerLevel>$(BuildNumber.Split('.')[3])</PowerLevel>
  </PropertyGroup>

  <Target Name="Dump">
    <Message Condition="$(PowerLevel)>9000" text="IT'S OVER 9000!" />
  </Target>
</Project>
1
2
Dump:
IT'S OVER 9000!

I’ve heard that there are some extensions out there that will split and assign to multiple properties a bit more fluidly, but this worked in a pinch. I’d be interested in hearing about other ways people have attacked this problem.

This post originally appeared on The DevStop.