如何使用msbuild替换文件中的字符串?

如何使用msbuild替换文件中的字符串?,msbuild,msbuild-task,msbuild-propertygroup,msbuild-buildengine,Msbuild,Msbuild Task,Msbuild Propertygroup,Msbuild Buildengine,我想使用ms build中的正则表达式将test.xml文件中的字符串“how r u”替换为另一个xy.xml文件中的字符串“I am fine” ie我必须从一个文件(xy.xml)中读取字符串,并将其替换到另一个文件test.xml中。 因此,请举例说明解决此问题的必要步骤。编辑:此答案已过时。使用下面的解决方案… 使用ReadLinesFromFile任务从xy.xml文件获取替换字符串 然后使用xy.xml中的值作为FileUpdate任务的替换字符串 把它们放在一起;) 这不再是必需

我想使用ms build中的正则表达式将test.xml文件中的字符串“how r u”替换为另一个xy.xml文件中的字符串“I am fine”

ie我必须从一个文件(xy.xml)中读取字符串,并将其替换到另一个文件test.xml中。
因此,请举例说明解决此问题的必要步骤。编辑:此答案已过时。使用下面的解决方案…

使用ReadLinesFromFile任务从xy.xml文件获取替换字符串

然后使用xy.xml中的值作为FileUpdate任务的替换字符串


把它们放在一起;)

这不再是必需的。。。现在可以将C#注入到项目/构建文件中

定义自定义任务和参数,如下所示:

<UsingTask TaskName="ReplaceFileText" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
  <ParameterGroup>
    <InputFilename ParameterType="System.String" Required="true" />
    <OutputFilename ParameterType="System.String" Required="true" />
    <MatchExpression ParameterType="System.String" Required="true" />
    <ReplacementText ParameterType="System.String" Required="true" />
  </ParameterGroup>
  <Task>
    <Reference Include="System.Core" />
    <Using Namespace="System" />
    <Using Namespace="System.IO" />
    <Using Namespace="System.Text.RegularExpressions" />
    <Code Type="Fragment" Language="cs">
      <![CDATA[
            File.WriteAllText(
                OutputFilename,
                Regex.Replace(File.ReadAllText(InputFilename), MatchExpression, ReplacementText)
                );
          ]]>
    </Code>
  </Task>
</UsingTask>



然后,只需像调用任何其他MSBuild任务一样调用它

<Target Name="AfterBuild">
  <ReplaceFileText 
    InputFilename="$(OutputPath)File.exe.config" 
    OutputFilename="$(OutputPath)File.exe.config" 
    MatchExpression="\$version\$" 
    ReplacementText="1.0.0.2" />
</Target>


上面的示例将输出目录中的“File.exe.config”中的“$version$”替换为“1.0.0.2”。

如本文所述,您可以使用MSBuild社区任务中的任务文件更新

我对位于Unix驱动器上的同一个文件运行了这两个替换,并使用了指向它的unc路径\server\path…:

<ReplaceFileText
  InputFilename="$(fileToUpdate)"
  OutputFilename="$(fileToUpdate)"
  MatchExpression="15.0.0"
  ReplacementText="15.3.1"/>


<FileUpdate Files="$(fileToUpdate2)"
            Regex="15.0.0"
            ReplacementText="15.3.1" />

并且上面的cs自定义操作不添加bom;但是,文件更新没有:

%head -2 branding.h branding2.h
==> branding.h <==
#/* branding.h
#** This file captures common branding strings in a format usable by both sed and C-preprocessor.

==> branding2.h <==
#/* branding.h
#** This file captures common branding strings in a format usable by both sed and C-preprocessor.
%head-2 branding.h branding 2.h
==>branding.h branding2.h的答案是好的,但它在DotNetCore上不起作用。我本想加上这个作为评论,但我没有足够的声誉

在DotNetCore上,您必须更新:

  • 任务工厂到“RoslynCodeTaskFactory”
  • 任务程序集到“$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll”
  • 删除对“System.Core”的引用
  • 消费目标必须将“后目标”属性指定为“构建”
其他一切都应该是一样的:

<Project Sdk="Microsoft.NET.Sdk.Web">
  ...

  <UsingTask
    TaskName="ReplaceFileText"
    TaskFactory="RoslynCodeTaskFactory"
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
      <InputFilename ParameterType="System.String" Required="true" />
      <OutputFilename ParameterType="System.String" Required="true" />
      <MatchExpression ParameterType="System.String" Required="true" />
      <ReplacementText ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System"/>
      <Using Namespace="System.IO"/>
      <Using Namespace="System.Text.RegularExpressions" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[  
          File.WriteAllText(
            OutputFilename,
            Regex.Replace(File.ReadAllText(InputFilename), MatchExpression, ReplacementText)
            );
        ]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="AfterBuildStep" AfterTargets="Build">
    <ReplaceFileText
       InputFilename="$(OutputPath)File.exe.config" 
       OutputFilename="$(OutputPath)File.exe.config" 
       MatchExpression="\$version\$" 
       ReplacementText="1.0.0.2" />
  </Target>
</Project>

...



更新了James的回答

  <UsingTask TaskName="ReplaceTextInFiles" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.$(VsBuildTaskBinarySuffix).dll">
<ParameterGroup>
  <MatchExpression ParameterType="System.String" Required="true" />
  <ReplacementExpression ParameterType="System.String" Required="true" />
  <InputFile ParameterType="Microsoft.Build.Framework.ITaskItem" Required="true" />      
  <IsTextReplaced ParameterType="System.Boolean"  Output="True"/>
</ParameterGroup>
<Task>
  <Reference Include="System.Core" />
  <Using Namespace="System" />
  <Using Namespace="System.IO" />
  <Using Namespace="System.Text.RegularExpressions" />
  <Code Type="Fragment" Language="cs">
    <![CDATA[
      bool isMatchFound = false;
      string filecontent = "";
      string path = InputFile.ItemSpec;

      Log.LogMessage(MessageImportance.High, "[ReplaceTextInFiles]: Match= " + MatchExpression);
      Log.LogMessage(MessageImportance.High, "[ReplaceTextInFiles]: Replace= " + ReplacementExpression);

      IsTextReplaced = false;
      using(StreamReader rdr = new StreamReader(path))
      {
        filecontent = rdr.ReadToEnd();
        if (Regex.Match(filecontent, MatchExpression).Success)
        {
          filecontent = Regex.Replace(filecontent, MatchExpression, ReplacementExpression);
          isMatchFound = true;            
        }
      }

      if(isMatchFound){
        using(StreamWriter wrtr = new StreamWriter(path))
        {
          wrtr.Write(filecontent);
          IsTextReplaced = true;
          Log.LogMessage(MessageImportance.Normal, "[ReplaceTextInFiles]: Replaced text in file:" + path);
        }
      }       
    ]]>
  </Code>
</Task>




如果您不喜欢使用第三方(社区)二进制文件,也不喜欢在msbuild项目中嵌入代码,我建议您创建一个简单的任务库,它实现并可以在以后承载其他任务:

使用System.IO;
使用Microsoft.Build.Framework;
使用Microsoft.Build.Utilities;
公共类FileWriteAllText:任务
{
[必需]
公共字符串路径{get;set;}
[必需]
公共字符串内容{get;set;}
公共重写bool Execute()
{
File.writealText(路径、内容);
返回true;
}
}
然后可以在msbuild中替换、追加等:

<UsingTask TaskName="FileWriteAllText" AssemblyFile="MyTasks.dll" />
<FileWriteAllText Path="test.xml"
     Contents="$([System.Text.RegularExpressions.Regex]::Replace(
         $([System.IO.File]::ReadAllText('test.xml')), 'how r u', 'i am fine'))" />

有一种非常简单的方法可以替换文件中的字符串:


c:\input.txt
c:\output.txt

探索内联C#代码<代码>[System.Text.RegularExpressions.Regex]
包含在列表中。

我必须从文件中读取具有属性名称对象的特定节点,并将此节点替换为另一个节点?如何处理此问题?这些任务来自MSBuildCommunityTasks项目,对于这样的简单任务,安装此项目可能非常不可取。您可以将编码参数传递到File.writealText以添加BOM,但无论哪种方法都可以完成:)如何将列表作为参数传递给do multiple replaces?有关支持项和正则表达式选项的增强版本,请参阅。我必须将ToolsVersion=“4.0”添加到项目标记中,以使其在正确的MSBuildToolsPath目录中查找。对于匹配表达式,我尝试了“[label]”,但在“label”时失败工作正常。请注意,.NET Core附带的MSBuild版本不支持CodeTaskFactory,因此这不是一个可移植的解决方案。请小心使用
Encoding=“Unicode”
!例如,
app.config
的默认值是
Encoding=“UTF-8”
,它不适用于Unicode!