Как я могу заменить любую строку на ее номер строки? - PullRequest
2 голосов
/ 05 февраля 2020

РЕДАКТИРОВАТЬ: После большой помощи @aschipfl, код на% 110 настолько функциональн, насколько я хотел! Я провел дополнительное исследование и упростил использование подсказок для этого дополнительного% 10: P

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Create a prompt to set the variables
set /p _FILETYPE="What file type: "
set /p _LINENUM="Which line: "
set /p _NEWLINE="Make line say: "

rem // Start the loop, and set the files
for %%f in (*%_FILETYPE%) do (
  set "_FILE=%%f"
  echo "_FILE=%%f"

rem // To execute seperate code before the end of the loop, starting at ":subroutine".
call :subroutine "%%f"
)

:subroutine
rem // Write to a temporary file:
> "%_FILE%.new" (
    rem /* Loop through each line of the original file,
    rem    preceded by the line number and a colon `:`:*/
    for /F "delims=" %%A in ('findstr /N "^" "%_FILE%"') do (
        rem // Store the current line with prefix to a variable:
        set "LN=%%A"
        rem /* Store the line number into another variable;
        rem    everything up to the first non-numeric char. is regarded,
        rem    which is the aforementioned colon `:` in this situation: */
        set /A "NUM=LN"
        rem // Toggle delayed expansion to avoid trouble with `!`:
        setlocal EnableDelayedExpansion
        rem /* Compare current line number with predefined one and replace text
        rem    in case of equality, or return original text otherwise: */
        if !NUM! equ %_LINENUM% (
            echo(!_NEWLINE!
        ) else (
            rem // Remove line number prefix:
            echo(!LN:*:=!
        )
        endlocal
    )
)
rem // Move the edited file onto the original one:
move /Y "%_FILE%.new" "%_FILE%"

endlocal
exit /B

ОРИГИНАЛЬНЫЙ ВОПРОС: Не имеет значения, что уже есть в любой из строк. Я просто хочу иметь возможность выбрать любую строку из .txt и заменить ее на то, что я выберу.

Так, например: Может быть, у меня есть куча .txt, и я хочу заменить строку 5 во всех них на "vanilla". А позже решите заменить строку 10 всех .txt на «Зеленый». И так далее ...

Я видел множество людей, задающих один и тот же главный вопрос. Но я продолжаю находить ситуативные ответы. "Как мне заменить указанные c строки?" «Вы ищете то, что уже есть в строке, и заменяете его новым текстом» - я не могу этого получить. Мне нужно, чтобы он был динамическим c, потому что в каждой «строке 5» есть разные значения или есть много других строк с тем же текстом.

Я попробовал единственный ответ, который смог найти, но все, что в итоге получилось, это заменить буквально все строки на «! ln: *: =!», а не на эхо.

@echo off
setlocal disableDelayedExpansion

set "file=yourFile.txt"
set "newLine5=NewLine5Here"

>"%file%.new" (
  for /f "delims=" %%A in ('findstr /n "^" "%file%"') do for /f "delims=:" %%N in ("%%A") do (
    set "ln=%%A"
    setlocal enabableDelayedExpansion
    if "!ln:~0,6!" equ "5:FMOD" (echo(!newLine5!) else echo(!ln:*:=!
    endlocal
  )
)
move /y "%file%.new" "%file%" >nul

Ответы [ 2 ]

2 голосов
/ 06 февраля 2020

Следующий (закомментированный) код должен работать для вас:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=yourFile.txt"
set "_NEWLINE=NewLine5Here"
set /A "_LINENUM=5" & rem // (target line number)

rem // Write to a temporary file:
> "%_FILE%.new" (
    rem /* Loop through each line of the original file,
    rem    preceded by the line number and a colon `:`:*/
    for /F "delims=" %%A in ('findstr /N "^" "%_FILE%"') do (
        rem // Store the current line with prefix to a variable:
        set "LN=%%A"
        rem /* Store the line number into another variable;
        rem    everything up to the first non-numeric char. is regarded,
        rem    which is the aforementioned colon `:` in this situation: */
        set /A "NUM=LN"
        rem // Toggle delayed expansion to avoid trouble with `!`:
        setlocal EnableDelayedExpansion
        rem /* Compare current line number with predefined one and replace text
        rem    in case of equality, or return original text otherwise: */
        if !NUM! equ %_LINENUM% (
            echo(!_NEWLINE!
        ) else (
            rem // Remove line number prefix:
            echo(!LN:*:=!
        )
        endlocal
    )
)
rem // Move the edited file onto the original one:
move /Y "%_FILE%.new" "%_FILE%"

endlocal
exit /B

Помимо опечатки в EnableDelayedExpansion в вашем коде, вам даже не нужна секунда for /F l oop, чтобы получить номер строки, и вам не нужно извлекать определенное количество символов из текста строки с префиксом.

Обратите внимание, что этот подход не работает для номеров строк, превышающих 2 31 - 1 = 2 147 483 647.

0 голосов
/ 05 февраля 2020

... заменяет буквально все строки на "! Ln: *: =!", А не на эхо.

Но это правильно, потому что FINDSTR /N ставит перед каждой строкой префикс перед номером строки.
!ln:*:=! только снова удаляет номер строки.
И трюк findstr используется, чтобы избежать пропуска пустых строк или строк, начинающихся с ; (символ EOL).

!line:*:=! заменяет все, вплоть до первого двойного двоеточия (и включая его), ничем.
Это лучше, чем использование FOR "delims=:", поскольку delims=: также лишит двойные двоеточия в начале строки.

Переключение отложенного расширения необходимо, чтобы избежать случайного удаления ! и ^ в строке set "ln=%%A"

К исправьте ваш код:

setlocal DisableDelayedExpansion
for /f "delims=" %%A in ('findstr /n "^" "%file%"') do (
    set "ln=%%A"
    setlocal EnableDelayedExpansion
    if "!ln:~0,6!" equ "5:FMOD" ( 
        set "out=!newLine5!"
    ) else (
        set "out=!ln:*:=!"
    )
    echo(!out!
    endlocal
)
...