批量修改文件中的值

时间:2018-07-05 09:08:40

标签: batch-file

大家晚上好

我对批处理文件一无所知,但是我需要它来做一些事情。

让我解释一下:我要做的是打开file.c并浏览此行代码

#define var ((uint32_t) 1000)

我想要的是通过用户先前输入的值来更改值1000,不同的是,每次用户输入值{{1}时,该值并不总是1000。 },
我希望将其替换为我的.c文件,然后需要替换250000个

250000

一次又一次地使用另一个变量,所以我希望我的程序替换定义var((uint32_t)之后的内容,并替换为用户输入的内容,希望您对我想做什么有所了解。 / p>

我添加了我的程序,但是它并没有真正起作用,请问您有什么想法吗?

#define var ((uint32_t) 250000)

1 个答案:

答案 0 :(得分:2)

用批处理脚本修改文本文件并不是一件容易的事,特别是当它的格式很容易被破坏时,即使仅添加或更改一个字符,例如(C)源代码。

尽管如此,我仍然不得不尝试使用纯批处理脚本来管理它-请参阅代码中的解释性说明。

主要挑战是:

  • 查找包含感兴趣的字符串#define var ((uint32_t) 1000)的行,该字符串可能在几乎任何位置都包含多个空格( SPACE TAB ),当然,除了关键字和数字之外
  • 提取数值并保留余数;为此,我依靠(不区分大小写)关键字uint32_t相对于数字的位置;

所以这里是

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=C:\Users\astre\Desktop\test\fichier.c" & rem // (path or name of input file)
set "_TEMP=%TEMP%\%~n0_%RANDOM%.tmp"              & rem // (path or name of temporary file)

rem // Gather TAB character:
for /F "delims=" %%T in ('forfiles /P "%~dp0." /M "%~nx0" /C "cmd /C echo/0x09"') do set "_T=%%T"
rem // Build white-space classes for search expressions:
set "_S=[ %_T%]" & set "_S0=[ %_T%]*" & set "_S1=[ %_T%][ %_T%]*"
rem // Build digit classes for search expressions:
set "_D=[0123456789]" & set "_D0=[0123456789]*" & set "_D1=[0123456789][0123456789]*"
rem // Define expression (word) before number to replace:
set "_SPLIT=uint32_t"
rem // Build search expression for `findstr`:
set "_SEARCH=^%_S0%#define%_S1%var%_S1%(%_S0%(%_S0%%_SPLIT%%_S0%)%_S1%%_D1%%_S0%)%_S0%$"

rem // Write output to temporary file:
> "%_TEMP%" (
    set "FLAG="
    rem /* Read input file line by line, prefixed by current line number,
    rem    so lines appear non-empty to `for /F`, which would be ignored: */
    for /F "delims=" %%L in ('findstr /N "^" "%_FILE%"') do (
        set "LINE=%%L"
        setlocal EnableDelayedExpansion
        set "LINE=!LINE:*:=!"
        rem // Check whether current line (without line number prefix) matches search expression:
        cmd /V /C echo(^^!LINE^^!| > nul findstr /R /I /C:"!_SEARCH!" && (
            rem /* Current line matches, so split it into two parts at certain expression (word);
            rem    the second part is the one that holds the number to replace later: */
            set "AFTER=!LINE:*%_SPLIT%=!"
            set "BEFORE=!LINE!|" & for /F "delims=" %%K in ("%_SPLIT%!AFTER!|") do set "BEFORE=!BEFORE:%%K=!"
            rem /* Toggle delayed expansion to avoid troubles with exclamation marks `!`;
            rem    this requires `setlocal`/`endlocal` pairs, which localise environments;
            rem    hence use `for /F` to transport some values over `endlocal` barrier;
            rem    the temporary underscores `_` ensure none of the tokens appear empty: */
            for /F "tokens=1* delims=| eol=|" %%G in ("_!BEFORE!|!AFTER!_") do (
                rem // Split the second part at number:
                for /F "tokens=1* delims=0123456789 eol=0" %%I in ("_!AFTER!_") do (
                    endlocal
                    set "FLAG=#"
                    set "BEFORE=%%G" & set "AFTER=%%H"
                    set "LEFT=%%I" & set "RIGHT=%%J"
                    setlocal EnableDelayedExpansion
                    rem // Append the part before the number to the first part:
                    set "BEFORE=!BEFORE:~1!%_SPLIT%!LEFT:~1!"
                    rem // Extract the number from the second part:
                    set "NUMBER=_!AFTER!|" & set "NUMBER=!NUMBER:*%%I=!" & set "NUMBER=!NUMBER:%%J|=!"
                    rem // Store the part after the number as the new second part:
                    set "AFTER=!RIGHT:~,-1!"
                )
            )
            rem // Prompt user for new number (keep old one as per default):
            set "ENTRY=!NUMBER!" & > con set /P ENTRY="Number (!ENTRY!): " && (
                rem // Verify that entry is purely numeric (with white-spaces ignored):
                set "ENTRY=!ENTRY: =!" & set "ENTRY=!ENTRY:%_T%=!"
                (for /F "delims=0123456789 eol=0" %%K in ("!ENTRY!") do rem/) && >&2 (
                    echo Number entry is not purely numeric; keeping former value !NUMBER!.
                ) || set "NUMBER=!ENTRY!"
            )
            rem // Return line with the number exchanged:
            echo(!BEFORE!!NUMBER!!AFTER!
        ) || (
            rem // Current line does not match search expression, so return it unedited:
            echo(!LINE:*:=!
        )
        endlocal
    )
)
rem // Move temporary file onto input file, but only if a search expression has been found:
if defined FLAG (
    > nul move /Y "%_TEMP%" "%_FILE%"
) else del "%_TEMP%"

endlocal
exit /B

Windows命令提示符cmd有一些限制:

  • 输入文本文件必须是ASCII / ANSI编码的;即使正确读取了Unicode文件,输出文件也会将编码更改为ASCII / ANSI;如果您可以接受,则必须使用code pages(可以尝试使用437850125265001一些广泛的转换;请参见chcp command)以找到合适的转换结果;
  • 输入文本文件必须包含纯ASCII字符; 0x7F以上代码的字符可能会转换为其他代码,具体取决于代码页;如果您可以接受,则可以再次更改代码页;
  • 输入文本文件必须包含DOS / Windows风格的换行符,即回车符(CR,代码0x0D),后跟换行符(LF,代码{{1}) }),简而言之:CR + LF;带有Unix风格的换行符(LF)的文件可能被正确读取,但是输出文件将包含DOS / Windows风格的换行符;具有MAC样式换行符(CR)的文件无法处理;
  • 输入文本文件中不得包含超过约8190个字符的任何行;