msbuildmsbuild-4.0

How to split string by multiple characters in MSBuild 4?


I have the following string called MasterVersion:

1.1-SNAPSHOT

I need to split it by the . and the - so it becomes a string[] array called SplitVersion, i.e.:

1
1
SNAPSHOT

I've tried everything I can think of including about a dozen variations of the below, with no joy:

<!-- doesn't work -->
<ItemGroup>
    <VersionDelimiters Include="." />
    <VersionDelimiters Include="-" />
    <SplitVersion Include="$(MasterVersion.Split(@VersionDelimiters))" />
</ItemGroup>

<!-- doesn't work either -->
<ItemGroup>
    <SplitVersion Include="$(MasterVersion.Split([`.`; `-`]))" />
</ItemGroup>

What obscure MSBuild syntax am I missing/mucking up?


Solution

  • MSBuild 4.0 property functions cannot handle arrays (well basically), however when you do a

    Split(`,`, `-`)
    

    You are invoking the String.Split(params string[]) overload, which requires an array (even in C# the params keyword will create an array behind the scene and do something like Split(new string[] { ',', '-' }) internally).

    What you could do is the following:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
     ToolsVersion="4.0">
    
        <PropertyGroup>
            <MasterVersion>1.1-SNAPSHOT</MasterVersion>
        </PropertyGroup>
    
        <ItemGroup>
            <SplitVersion Include="$(MasterVersion.Replace(`-`, `.`).Split(`.`))" />
        </ItemGroup>
    
        <Target Name="Test">
            <Message Importance="high" Text="@(SplitVersion)"/>
        </Target>
    </Project>
    

    Or you could first create the (string) array to be passed to Split:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
        <PropertyGroup>
            <MasterVersion>1.1-SNAPSHOT</MasterVersion>
            <Delimiters>.;-</Delimiters>
            <DelimitersArray>$(Delimiters.Split(`;`))</DelimitersArray>
        </PropertyGroup>
        <ItemGroup>
            <SplitVersion Include="$(MasterVersion.Split($(DelimitersArray)))" />
        </ItemGroup>
        <Target Name="Test">
            <Message Importance="high" Text="@(SplitVersion)"/>
        </Target>
    </Project>
    

    Which is not really better in this case ;-)

    Oh, and you might want to check out this MSDN blog entry for more useful information.

    Update for a comment:

    Example:

    <PropertyGroup>
      <SplitVersion0>$(MasterVersion.Split($(DelimitersArray))[0])</SplitVersion0>
      <SplitVersion1>$(MasterVersion.Split($(DelimitersArray))[1])</SplitVersion1>
      <SplitVersion2>$(MasterVersion.Split($(DelimitersArray))[2])</SplitVersion2>
    </PropertyGroup>
    

    The array-indexing operator works here, because in this case you are still "in the context" of the .NET expression. Once that is assigned to a property (or item group) you cannot do that anymore.