我有多个文本(.cs)文件都有类似于这样的行:
public partial class ApiIThis : IEquatable<ApiIThis>
或
public partial class ApiIThat : IEquatable<ApiIThat>
我需要将它们转换为
public partial class ApiIThis : IEquatable<ApiIThis>, IThis
public partial class ApiIThat : IEquatable<ApiIThat>, IThat
这将在需要在.bat
环境中运行的Windows command line
文件中运行
更新:回答@aschipfl
到目前为止你尝试了什么,你有什么问题?请 通过在问题中添加信息来分享您的努力!
到目前为止,我所做的是在谷歌搜索中找到一些我正在尝试做的例子。我发现SO帖子(How to replace substrings in windows batch file)看起来有点相关,但这还不足以让我离开。
无论如何,.cs文件只有你所展示的行,甚至一行 仅?
不,这些不是文件中的唯一行。这些文件将包含C#
工具自动生成的完整Swagger
类。
你是否需要在其他行之间找到它们,如果是,那么通过什么 标准是什么?
是的,他们将在其他行之间。但是,它将是文件中唯一这样的行。该文件的定义如下:
using Something;
using SomethingElse;
public partial class ApiIThis : IEquatable<ApiIThis>
{
public ApiIThis()
{
/* Other code here */
}
/* Other code here */
}
课后和中间的单词总是匹配吗?
是的,它们将始终匹配。
单词可能包含空格吗?
不,它们永远不会包含空格。
是否要在单个输出文件中收集转换后的行, 或者你想为每个输入文件单独输出文件?或者你甚至 想要覆盖/替换原始文件?
我希望更新原始文件。
最后,我想补充说,它们都将以Api
开头,实际上ApiI
答案 0 :(得分:2)
@echo off
setlocal EnableDelayedExpansion
rem Process all *.cs files
for %%a in (*.cs) do (
echo Processing "%%a"
rem Get the number of the target line
for /F "delims=:" %%b in ('findstr /N /C:"public partial class" "%%a"') do set /A "skip=%%b-1"
rem Read from original file
< "%%a" (
rem Copy previous lines
for /L %%i in (1,1,!skip!) do (
set "line="
set /P "line="
echo/!line!
)
rem Process target line
set /P "line="
for /F "tokens=4,6" %%b in ("!line!") do (
set "Api=%%b"
echo public partial class %%b : %%c, !Api:~3!
)
rem Copy rest of lines
findstr "^"
rem Write to new file
) > "%%~Na.new"
move /Y "%%~Na.new" "%%a"
)
编辑:我使用OP提供的文件测试了此解决方案。令人惊讶的是,这些文件 NOT 以CR + LF对结束,但只是在LF(Linux风格)中,因此必须将它们转换为CR + LF标准才能由批处理文件处理(使用Windows标准)。
我使用more
命令以这种方式转换文件:
for %a in (*.cs) do more %a > %~Na.new
del *.cs
ren *.new *.cs
之后转换是正确的,除了可以直接插入相应echo
命令的行开头的4个空格。
C:\> test.bat
Processing "ApiIClaim.cs"
Processing "ApiIClaimType.cs"
Processing "ApiIMonetaryType.cs"
C:\> for %a in (*.cs) do @fc %a %~Na.new
Comparando archivos ApiIClaim.cs y APIICLAIM.NEW
***** ApiIClaim.cs
[DataContract]
public partial class ApiIClaim : IEquatable<ApiIClaim>
{
***** APIICLAIM.NEW
[DataContract]
public partial class ApiIClaim : IEquatable<ApiIClaim>, IClaim
{
*****
Comparando archivos ApiIClaimType.cs y APIICLAIMTYPE.NEW
***** ApiIClaimType.cs
[DataContract]
public partial class ApiIClaimType : IEquatable<ApiIClaimType>
{
***** APIICLAIMTYPE.NEW
[DataContract]
public partial class ApiIClaimType : IEquatable<ApiIClaimType>, IClaimType
{
*****
Comparando archivos ApiIMonetaryType.cs y APIIMONETARYTYPE.NEW
***** ApiIMonetaryType.cs
[DataContract]
public partial class ApiIMonetaryType : IEquatable<ApiIMonetaryType>
{
***** APIIMONETARYTYPE.NEW
[DataContract]
public partial class ApiIMonetaryType : IEquatable<ApiIMonetaryType>, IMonetaryType
{
*****
答案 1 :(得分:1)
以下脚本 - 让我们称之为append-keyword.bat
- 做你想做的事。要使用它,请提供要作为命令行参数处理的所有文件;还允许使用通配符?
和*
:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "TMPF=%TEMP%\%~n0_%RANDOM%.tmp"
:LOOP
set "ARGF=%~1"
if defined ARGF (
setlocal EnableDelayedExpansion
for %%F in ("!ARGF!") do (
endlocal
if /I not "%%~fF"=="%~f0" (
set "FILE=%%~fF"
setlocal EnableDelayedExpansion
if exist "!FILE!" if not exist "!FILE!\" (
rem /* (it's a file but not a dir. due to "\") */
> "!TMPF!" call :PROCESS MOV "!FILE!"
if defined MOV (
> nul move /Y "!TMPF!" "!FILE!"
) else (
> nul del "!TMPF!"
)
)
) else (
setlocal EnableDelayedExpansion
)
)
endlocal
shift /1
goto :LOOP
)
endlocal
exit /B
:PROCESS return item
setlocal DisableDelayedExpansion
set "ITEM=%~2"
set "RTN="
setlocal EnableDelayedExpansion
for /F delims^=^ eol^= %%L in ('findstr /N /R "^^" "!ITEM!"') do (
endlocal
set "LINE=%%L"
set "SKIP="
rem // Default delimiters TAB and SPACE:
setlocal EnableDelayedExpansion
for /F "eol=/ tokens=1-3,*" %%A in ("!LINE:*:=!") do (
endlocal
if "%%A %%B %%C"=="public partial class" (
rem // Delimiters `:`, TAB and SPACE:
for /F "eol=/ tokens=1,* delims=: " %%E in ("%%D") do (
rem // Delimiters `<`:
for /F "eol=/ tokens=1,* delims=<" %%G in ("%%F") do (
if "%%G"=="IEquatable" (
rem // Delimiters `>`, `,`, TAB and SPACE:
for /F "eol=/ tokens=1,* delims=>, " %%I in ("%%H") do (
if "%%J"=="" (
if "%%E"=="%%I" (
set "STR=%%E"
setlocal EnableDelayedExpansion
if "!STR:~,3!"=="Api" (
echo(!LINE:*:=!, !STR:~3!
endlocal
set "SKIP=#"
) else (
endlocal
)
)
)
)
)
)
)
)
setlocal EnableDelayedExpansion
)
if not defined SKIP (
echo(!LINE:*:=!
) else (
endlocal
set "RTN=#"
setlocal EnableDelayedExpansion
)
)
endlocal
endlocal & set "%~1=%RTN%"
exit /B
主程序完成以下任务:
for
循环解析通配符; 子程序执行以下操作:
public
,partial
,class
,而不是检查其间的空白数量; (请注意,不检查单词是否后跟冒号!)IEquatable
,然后检查<
,更多文字和>
; class
之后和<
与>
之间的字词是否匹配; (认为后一个字符串不能单独包含<
,>
或,
!)Api
开头,将其剪切并将剩余的字符串附加到该行,由,
和 SPACE 分隔; echo
)修改后的行或原始行,具体取决于上述所有检查是否成功; 答案 2 :(得分:-1)
这是一个使用PowerShell的脚本(自Vista以来所有Windows,通过更新安装在XP上)。
Param(
[String]
$input_file
)
Function Filter-Data
{
Param(
[Parameter(ValueFromPipeline=$True)]
[String]
$line
)
Process {
if ($line -match "public\s+partial\s+class\s+ApiI([A-Za-z0-9_]+)\s*:\s*IEquatable\s*<\s*ApiI[A-Za-z0-9_]+\s*>") {
Return $matches[0] + ", " + $matches[1]
} Else {
Return $line
}
}
}
Get-Content $input_file | Filter-Data | Write-Host
你给它输入文件名。它吐出过滤后的数据。您可能希望使过滤更加智能化(允许空格等),但是这里的功能可以解决问题。
调用可能如下所示:
PowerShell -NoProfile -ExecutionPolicy Bypass -File filter.ps1 source_file.cs <NUL
笔记
-NoProfile
会告诉PoSH不要加载用户的个人资料(启动速度更快)-ExecutionPolicy
必须允许文件,如果您尚未在计算机上配置文件,则需要指定ByPass
以便PoSH运行脚本。<NUL
PowerShell经常在完成执行之前等待您按ENTER键。在脚本完成后,将任何内容重定向都不会将控制权返回给调用者。编辑根据添加到问题的详细信息和关于琐事的评论,我更新了过滤代码,以便更一般地匹配和替换。它还允许C#令牌之间的空格,即使这不是官方要求(我不完全信任代码生成器)。