Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 862
Ian Kemp Avatar asked Jan 16 '12 15:01

Ian Kemp


People also ask

How do I split a string into multiple characters?

To split a String with multiple characters as delimiters in C#, call Split() on the string instance and pass the delimiter characters array as argument to this method. The method returns a String array with the splits.

How split a string after a specific character in C#?

Split(char[], StringSplitOptions) Method This method is used to splits a string into substrings based on the characters in an array. You can specify whether the substrings include empty array elements. Syntax: public String[] Split(char[] separator, StringSplitOptions option);


1 Answers

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:

  • The "content" of SplitVersion is technically an "array of ITaskItem", yes. You would deal with it however you would deal with Items (of ItemGroups); including things like "batching", etc.

  • You cannot really "access things by index" in msbuild project files. Expressions like $(SplitVersion)[0] or @(SplitVersion)[0] or @(SplitVersion[0]) don't do what you'd think/like. If you really would to you could assign individual properties for "array elements" by "index".

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.

like image 53
Christian.K Avatar answered Oct 26 '22 07:10

Christian.K