Как вы можете найти и заменить символ в текстовом файле в командной строке Windows строка за строкой, но от конкретного символа появляются счетчики? - PullRequest
0 голосов
/ 16 мая 2019

У меня есть текстовый файл с разделителем точек с запятой (CSV), он имеет 65 столбцов, но последний - это столбец «комментариев», в котором могут быть точки с запятой.
Я хотел бы знать, как писать окнаПакетный файл, который считает точки с запятой в каждой строке и, если он находит> 64 точки с запятой,
удаляет все точки с запятой, которые следуют после 64 (или изменяются с запятой).(У меня нет доступа к источнику, который создает текстовые файлы)

Пример актуален:

marshal;Stevens;Son;11223344;Dual;this person tries food; water; fruit

Ожидаемый результат:

marshal;Stevens;Son;11223344;Dual;this person tries food, water, fruit

Ответы [ 3 ]

2 голосов
/ 16 мая 2019
@ECHO OFF
SETLOCAL 
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q56171667.txt"
SET "outfile=%destdir%\outfile.txt"
(
FOR /f "usebackqtokens=1*delims=" %%a IN ("%filename1%") DO (
 SET "line=%%a"
 CALL :lop64
)
)>"%outfile%"

GOTO :EOF

:: remove the first 64 ;-terminated strings from LINE
:: remove remaining `;`

:lop64
SET /a lopoff=64
SET "original=%line%"
:lop64lp
SET "line=%line:*;=%"
SET /a lopoff-=1
IF %lopoff% gtr 0 GOTO lop64lp
CALL ECHO %%original:;%line%=%%;%line:;=%
GOTO :eof

Вам потребуется изменить настройки sourcedir и destdir в соответствии с вашими обстоятельствами.

Я использовал файл с именем q56171667.txt, содержащий некоторые фиктивные данные для моего тестирования.

Создает файл, определенный как% outfile%

Опция usebackq требуется только потому, что я решил добавить кавычки вокруг имени исходного файла.

Обработка текста в пакете - этоминное поле.Возможно, вам лучше использовать sed или (g)awk, предназначенные для этой задачи.

Я предполагаю, что в отсутствие информации иначе, что ваши данные не содержат символов, которые имеют особое значение дляПакетный как % или " или & или | или < или > среди других.

По существу, присвойте всю прочитанную строку как line, затем в подпрограммезамените ничем для каждой строки до ; (:*;=) 64 раза.Затем покажите исходную строку с остатком в line, замененным ничем , объединенным с ; и остатком line с ;, замененным ничем (:;=).Если вы хотите использовать запятую вместо точки с запятой, используйте :;=, здесь.

1 голос
/ 16 мая 2019

Несмотря на то, что вы не приложили никаких усилий для решения своей задачи, я решил предоставить некоторый код, потому что это хороший вызов - см. Все пояснительные замечания rem:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=%~1"  & rem // (input file; `%~1` is the first command line argument)
set "_SEP=;"     & rem // (original separator to be replaced)
set "_NEW=,"     & rem // (new separator to replace the old one with)
set /A "_LIM=64" & rem // (number of first original separators to be kept)

rem // Read input file line by line:
for /F usebackq^ delims^=^ eol^= %%L in ("%_FILE%") do (
    rem // Store current line, reset some auxiliary variables:
    set "LINE=%%L" & set "COLL=" & set /A "CNT=-1"
    setlocal EnableDelayedExpansion
    rem // Handle the case when no original separator is defined:
    if defined _SEP (
        rem // Iterate through all separated items of the current line:
        for %%I in ("!LINE:%_SEP%=" "!") do (
            rem // Support loop to transport `COLL` variable over `endlocal` barrier:
            for /F "delims=" %%J in (""!COLL!"") do (
                endlocal
                rem /* Store currently iterated item, increment item counter and
                rem    store rebuilt line with separators replaced as defined: */
                set "ITEM=%%~I" & set /A "CNT+=1" & set "COLL=%%~J"
                setlocal EnableDelayedExpansion
                rem // Check whether or not to exclude current separator:
                if !CNT! gtr %_LIM% (
                    set "COLL=!COLL!!_NEW!!ITEM!"
                ) else if !CNT! gtr 0 (
                    set "COLL=!COLL!!_SEP!!ITEM!"
                ) else set "COLL=!ITEM!"
            )
        )
        rem // Return rebuilt line with separators replaced as defined:
        echo(!COLL!
    ) else echo(!LINE!
    endlocal
)

endlocal
exit /B

Учитываясценарий сохраняется как repl-sep.bat, а входной файл называется 1.csv, запустите сценарий следующим образом:

repl-sep.bat "1.csv"

Чтобы сохранить выходные данные в файле с именем 2.csv, а не отображать его вконсоль, используйте эту командную строку:

repl-sep.bat "1.csv" > "2.csv"

Обратите внимание, что во входном файле не должно быть следующих символов: ?, *, <, >, ".

0 голосов
/ 16 мая 2019

В идеале вы должны прочитать в файле с for /f и использовать "tokens=64*delims=;"
, чтобы получить остаток строки и заменить только точки с запятой там.

К сожалению, максимальное значение токенов равно 31 (плюс * остаток), поэтому вам нужно вложить несколько for /F

:: Q:\Test\2019\05\16\SO_56171667.cmd
@Echo off
Set "FileIn=Col65.csv"
Set "FileOut=NewCol65.csv"

(    for /F "usebackq  delims="  %%a in ("%FileIn%"
) do for /F "tokens=31*delims=;" %%b in ("%%a"
) do for /F "tokens=31*delims=;" %%d in ("%%c"
) do for /f "tokens=2* delims=;" %%f in ("%%e"
) do Call :Sub "%%a" "%%g"
)>"%FileOut%"

Goto :Eof
:Sub
Set "Line=%~1#"
Set "Col65=%~2"
Set "Col65=%Col65:;=,%"
Call Echo:%%Line:%~2#=%Col65%%%

Помимо времени загрузки, этот скрипт PowerShell может быть быстрее с большимифайлы:

## Q:\Test\2019\05\16\SO_56171667_2.ps1
$FileIn  = 'Col65.csv'
$FileOut = 'NewCol65.csv'
Get-Content $FileIn | ForEach-Object{
  $Cols = $_ -split ';',65
  $Cols[-1] = $Cols[-1].Replace(';',',')
  $Cols -join ';'
} | Set-Content $FileOut

по теме, упакованные в пакет:

:: Q:\Test\2019\05\16\SO_56171667_2.cmd
@Echo off
Set "FileIn=Col65.csv"
Set "Fileout=NewCol65.csv"

powershell -NoP -C "gc '%FileIn%'|ForEach-Object{$Cols=$_ -split ';',65;$Cols[-1]=$Cols[-1].Replace(';',',');$Cols -join ';'}|Set-Content '%FileOut%'"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...