Войти

Показать полную графическую версию : [решено] Удаления строки ниже найденого текста.


Страниц : [1] 2

Grade24
15-08-2019, 10:45
Друзья, всем привет. Обычно по bat много инфы и все мои задачи давно уже решались и я их с легкостью находил, но сейчас не смог найти решение. Помогите пожалуйста.

Есть текстовый файл вида.

произвольный текст
произвольный текст
произвольный текст txt1 произвольный текст
произвольный текст
произвольный текст
произвольный текст txt1 произвольный текст
произвольный текст
произвольный текст txt1 произвольный текст
произвольный текст
произвольный текст
произвольный текст

Где:
произвольный текст - это различный текст, не повторяющийся текст.
text1 - это текст который не изменяется.

Задача, найти в текстовом файле текст "txt1" удалить строчку где находиться этот текст и строчку ниже.

Iska
15-08-2019, 11:08
Есть текстовый файл вида. »
Упакуйте его в архив и приложите к сообщению.

text1 - это текст который не изменяется. »
Приведите конкретный пример содержимого text1 на основании файла, упакованного в архив.

Вас устроит рещение на WSH/PowerShell?

Grade24
15-08-2019, 13:01
Спасибо за быстрый ответ. Увы в файле есть информация которую не могу выложить. Но думаю Вы поймете вчем суть для примера прилагаю файл.

В файле 12 строк, в файле есть три строки где присутствует текст txt1 в строчках 5,7 и 11. Необходимо удалить эти строчки (5,7,11) и удалить строчки после них, строчки 6,8,12.

Рабочий файл содержить почти 4000 строк. Текст по которому ищем строчки (text1) может расспологаться в различных строчках.

Вас устроит рещение на WSH/PowerShell? »
Да, вполне.

YuS_2
15-08-2019, 13:58
Текст по которому ищем строчки (text1) может расспологаться в различных строчках. »
А если строки будут расположены так:
1. произвольный текст
2. произвольный текст txt1 произвольный текст
3. произвольный текст txt1 произвольный текст
4. произвольный текст
По Вашему условию: удаляется строка №2, т.к. в ней содержится маркер "txt1" и за ней сразу же удаляется строка №3, т.к. это последующая строка за строкой с маркером.
Проверить маркер в строке №3 мы уже не можем, т.к. строка удалена...
В сухом остатке: строку №4 удалять уже нельзя, т.к. не выполняются необходимые условия.
А как должно быть?

Grade24
15-08-2019, 14:03
По Вашему условию: удаляется строка №2, т.к. в ней содержится маркер "txt1" и за ней сразу же удаляется строка №3, т.к. это последующая строка за строкой с маркером.
Проверить маркер в строке №3 мы уже не можем, т.к. строка удалена...
В сухом остатке: строку №4 удалять уже нельзя, т.к. не выполняются необходимые условия.
А как должно быть? »
Все нормально, такого не будет, после строчки с txt1 всегда идет строчка без txt1

Iska
15-08-2019, 14:37
А если строки будут расположены так: »
А я даже не подумал о таком варианте :(.

in866.rar »
На всякий случай спрошу. Файл у вас именуется in866.txt, но кодировку имеет UTF-8 с BOM. Так и должно быть? И последняя строка в Вашем образце не завершается символами конца строки — это тоже верно, так и есть?

YuS_2
15-08-2019, 15:01
Все нормально, такого не будет, после строчки с txt1 всегда идет строчка без txt1 »
Ну, если есть уверенность, это хорошо, но т.к. нет полных исходных данных, то лучше учесть всякие варианты...
Примерно так:
powershell
$file = '.\in866.txt'
$mrk = 'txt1'
$enc = 'utf8'

$a = gc $file -enc $enc|%{$flg1,$flg2=$false,$false}{
if($_ -match $mrk){
$flg1=$true
$flg2=$true
} elseif ($flg1 -and $flg2){
$flg2=$false
} else {
$_
$flg1=$false
$flg2=$true
}
}
$a|sc $file -enc $enc
в том числе, будет работать, если есть парные строки с маркером.

А я даже не подумал о таком варианте »
Дык, всего на свете учесть невозможно.
Просто приходилось сталкиваться с подобной постановкой задачи, когда прилегающие, контекстные строки надо было учитывать... кстати, тот код ваял ещё на cmd и если хорошо поискать, то возможно даже он найдется... :)

Grade24
15-08-2019, 15:20
YuS_2,
Спасибо за код, увы не работает. Может что-то нетак делаю. Создал файл 123.bat, файл находиться в тойже папке что и файл in866.txt, запускай 123.bat, но нечего не меняется... Что я делаю нетак ? Пробовал в первой строчке прописать полный путь до файла in866.txt, не помогло.

Ну, если есть уверенность, это хорошо, но т.к. нет полных исходных данных, то лучше учесть всякие варианты... »
Я просто не стал углубляться в структуру исходного файла, не хотел вам забивать голову. Если пригодиться расскажу )) Постараюсь максимально понятно объяснить...

Файл состоит из блоков строк, один блок - это две строки, между блоками нет пустых строк. У всех блоков произвольный, разный, не повторяющийся текст. Но есть блоки где первая строчка содержит текст txt1 эти блоки необходимо удалить, тоесть удалить первую и вторую строчку блока.

Iska
15-08-2019, 15:45
Создал файл 123.bat, »
Это не пакетный файл, это скрипт PowerShell.

А на мои вопросы:
На всякий случай спрошу. Файл у вас именуется in866.txt, но кодировку имеет UTF-8 с BOM. Так и должно быть? И последняя строка в Вашем образце не завершается символами конца строки — это тоже верно, так и есть? »
ответите?

YuS_2
15-08-2019, 17:21
Создал файл 123.bat, файл находиться в тойже папке что и файл in866.txt, запускай 123.bat, но нечего не меняется... Что я делаю нетак ?»
Если по-простому, то всё не так... :)
То, что это не batch-сценарий, уже написали...
В общем, скрипт необходимо сохранить в текстовом файле, с кодировкой UTF8 с BOM (это не единственная кодировка, но лучше в ней). Файл можно именовать как угодно, но расширение должно быть .ps1
Например: script.ps1
Далее, есть варианты...
Скрипт можно запускать непосредственно из консоли powershell, либо ПКМ на файле скрипта и выбрать соответствующий пункт контекстного меню, либо создать batch-сценарий, например, run.bat:
@echo off
echo Выполняем...
powershell -ex bypass .\script.ps1
echo Готово.
pause
и запускать сценарий powershell уже этим пакетным файлом...
В общем, выбор за Вами...

greg zakharov
15-08-2019, 21:19
Проще всего задача решается с помощью sed:
sed "/txt1/,+1 d" input.txt
В итоге из:
1произвольный текст
2произвольный текст
3произвольный текст txt1 произвольный текст
4произвольный текст
5произвольный текст
6произвольный текст txt1 произвольный текст
7произвольный текст
8произвольный текст txt1 произвольный текст
9произвольный текст
10произвольный текст
11произвольный текст
Получим:
1произвольный текст
2произвольный текст
5произвольный текст
10произвольный текст
11произвольный текст

Iska
16-08-2019, 14:13
Добавлю и своё до кучи (на PowerShell):
$sSourceFile = 'C:\Мои проекты\0272\in866 2.txt'
$sString4Find = 'txt1'


$sPattern = ".*$sString4Find.*`r`n.*(?:`r`n|$)"

if([System.IO.File]::Exists($sSourceFile)) {
$sContent = Get-Content -Path $sSourceFile -Encoding UTF8 -Raw

if([Regex]::IsMatch($sContent, $sPattern)) {

[Regex]::Replace($sContent, $sPattern, '') | Set-Content -Path $sSourceFile -Encoding UTF8 -NoNewline
Write-Host "Found [$sString4Find] and replaced in content of source file [$sSourceFile]." -ForegroundColor Green
} else {
Write-Host "Not found [$sString4Find] in content of source file [$sSourceFile]." -ForegroundColor Red
}
} else {
Write-Host "Can't find source file [$sSourceFile]." -ForegroundColor Red
}

Grade24
16-08-2019, 14:17
Друзья большое всем спасибо за помощь, то что нужно.

Использую этот код, без паузы в конце.
@echo off
echo Выполняем...
powershell -ex bypass .\script.ps1
echo Готово.
pause

Для запуска этого.

$file = '.\in866.txt'
$mrk = 'txt1'
$enc = 'utf8'

$a = gc $file -enc $enc|%{$flg1,$flg2=$false,$false}{
if($_ -match $mrk){
$flg1=$true
$flg2=$true
} elseif ($flg1 -and $flg2){
$flg2=$false
} else {
$_
$flg1=$false
$flg2=$true
}
}
$a|sc $file -enc $enc

Ребята, еще раз, от души спасибо. Нужно сделать на форуме кнопки доната для пользователей. Готов задонатить.

Кстати, если искать текст (маркер) вида 123+, то удаляет больше строк чем нужно. Возможно из-за "+", для меня это не критично.

Попробую код от Iska

Iska
16-08-2019, 15:43
Кстати, если искать текст (маркер) вида 123+, то удаляет больше строк чем нужно. Возможно из-за "+", для меня это не критично. »
Всё так. «+» в шаблоне регулярного выражения имеет специальный смысл — это квалификатор, означающий «предыдущий символ шаблона должен встретиться один или более раз». Чтобы использовать сам символ плюс, нужно его экранировать другим специальным символом:
123\+
Вот здесь: Элементы языка регулярных выражений — краткий справочник | Microsoft Docs (https://docs.microsoft.com/ru-ru/dotnet/standard/base-types/regular-expression-language-quick-reference) Вы можете загрузить (Загрузить в формате Word (DOCX) Download in Word (.docx) format (https://download.microsoft.com/download/D/2/4/D240EBF6-A9BA-4E4F-A63F-AEB6DA0B921C/Regular%20expressions%20quick%20reference.docx)) краткую справку по символам регулярных выражений .Net Framework.

AKadekin
19-08-2019, 09:26
Добрый день, как в PowerShell в скрипте ps сохранить результат не в utf8 c BOM а в формате utf8 без BOM

Iska
19-08-2019, 15:24
Примерно так (http://forum.oszone.net/post-2884707.html#post2884707).

DJ Mogarych
23-08-2019, 13:52
YuS_2, а разъясните, пожалуйста, как вот это работает:
% {$flg1,$flg2=$false,$false}{...}
Почему после % идёт два скриптблока, и что задаётся в первом?

Iska
23-08-2019, 14:20
DJ Mogarych, насколько я понимаю, % — псевдоним командлета ForEach-Object, который поддерживает три скрипт-блока — Begin, Process и End. В данном случае использованы скрипт-блоки Begin и Process. Соответственно, в первом скрипт-блоке Begin двум переменным просто присваиваются два булевых значения, запись вида:
$flg1,$flg2=$false,$false
аналогична более привычной записи:
$flg1=$false
$flg2=$false
Данная конструкция, именуемая «параллельное присваивание (https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B8%D1%81%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5#%D0%9F%D0%B0%D1%80%D0%B0%D0 %BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B5_%D0%BF%D1%80%D0%B8%D1%81%D0%B2%D0%B0%D0%B8%D0%B2%D0%B0 %D0%BD%D0%B8%D0%B5)», вида «список переменных=список выражений», присутствует во многих современных языках — Lua, Python и пр.

greg zakharov
23-08-2019, 15:11
В случае с PowerShell можно было бы обойтись "многострочной" регуляркой, в смысле захватываем строку соответствующую критерию и следующую строку за ней. Это будет работать за рядом оговорок, но можно сделать несколько иначе.
$indexes = ($content = Get-Content .\file.txt -Encoding utf8) |
Select-String txt1 | ForEach-Object {++($$ = ,(--$_.LineNumber) * 2)[1];$$}

0..($content.Length - 1) | Where-Object {$indexes -notcontains $_} |
ForEach-Object {$content[$_]} | Out-File .\cleaned.txt -Encoding utf8
В более поздних нежели v2 версиях PowerShell, данный подход можно еще более сократить за счет оператора -notin, методов расширений и т.д., в результате чего решение будет похоже скорее на black magic, примерно такое же как в случае с "многострочной" регуляркой.

YuS_2
23-08-2019, 17:42
разъясните, пожалуйста, как вот это работает »
Да, Iska, верно описал работу конструкции и добавить особо нечего...
А если, что-нибудь забудется, то можно всегда освежить в памяти, с подробностями и примерами:
man foreach-object -s




© OSzone.net 2001-2012