Войти

Показать полную графическую версию : Выделить подстроки из текстового файла и записать их в пару переменных


HankHank
27-01-2022, 11:16
Привет.

Возникла задача, связанная с обработкой текстового файла.

Предыстория в следующих двух абзацах. Её можно пропустить.

Фонотека на дисках USB HDD структурирована определённым образом. В ней используются точки соединения - JUNCTION. Изначально предполагалось работать с этими дисками, монтируя тома каждый раз на букву “H:”.
Однако, спустя время, с монтированием заморачиваться поднадоело.
И для этого в файловой системе NTFS появились относительные символьные ссылки – SYMLINKD.
Процедура замены JUNCTION на SYMLINKD понятна. Для этого есть соответствующая команда NTLinks Maker http://wincmd.ru/plugring/NTLinksMaker.html .
Также понятно, как вывалить информацию обо всех JUNCTION в файл:

@chcp 1251 >nul
dir /AL /S H:\ >JtoS.txt

В итоге файл JtoS.txt содержит регулярную структуру данных. Например:


Том в устройстве H имеет метку 2 NTFS
Серийный номер тома: CAE4-9F0A


Содержимое папки H:\Слушать\Слушать\ Инструменты\Труба (trumpet)

09.12.2010 23:43 <JUNCTION> Baldauf Rudiger [\??\H:\Фонотека\Jazz - fusion\Baldauf Rudiger]
29.10.2011 02:21 <JUNCTION> Beiderbecke Leon Bix [\??\h:\Фонотека\Jazz\Beiderbecke Leon Bix]
...
0 файлов 0 байт
...

Содержимое папки H:\Слушать\Слушать\Modern jazz

09.10.2010 08:28 <JUNCTION> Lloyd Charles [\??\H:\Фонотека\Jazz - avant-guard\Lloyd Charles]
0 файлов 0 байт

Содержимое папки H:\Слушать\Слушать\Smooth

23.08.2010 21:29 <JUNCTION> Blake Aaron - Desire (2007) [\??\H:\Фонотека\Jazz - smooth\Aaron Blake\Blake Aaron - Desire (2007)]
02.09.2010 18:56 <JUNCTION> Club des Belugas - Swop (2008) [\??\H:\Фонотека\Jazz - smooth\ Various\Club des Belugas - Swop (2008)]
...
0 файлов 0 байт

Всего файлов:
1 файлов 0 байт
665 папок 316*940*726*272 байт свободно


Очевидно, что вся информация, нужная для реорганизации дисков, присутствует.

Формально нужно организовать цикл по секциям, начинающимся со строк “Содержимое папки”.
В каждой секции пройти по строкам, содержащим “<JUNCTION>”, каждый раз в переменную %t помещая содержимое квадратных скобок без символов “\??\” (целевой объект), а в переменную %l – ссылку.

Для первого вхождения:
%t = “H:\Фонотека\Jazz - fusion\Baldauf Rudiger”,
%l = “H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Baldauf Rudiger”.
Для второго вхождения:
%t = “h:\Фонотека\Jazz\Beiderbecke Leon Bix”,
%l = “H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Beiderbecke Leon Bix”.
и т.д.

%t лежит внутри “[\??\ ... ]”.
%l образуется конкатенацией строки, стоящей следом за “Содержимое папки” , бэк-слеша и строки, стоящей между “<JUNCTION>” и строкой ”[\??\“ без лидирующих и замыкающих пробелов.

В именах файлов, кроме русских букв, могут встречаться спецсимволы (,;:_ и т.п.).

Помогите, плиз, с шаблоном обработки.
Саму процедуру замены с удалением JUNCTION и созданием SYMLINKD вставлю в шаблон самостоятельно.

Спасибо заранее.

megaloman
27-01-2022, 16:57
Не думаю, что эта задача может быть надежно реализована в CMD из-за спецсимволов. Попробуйте формальное решение:@Echo Off
cls
>nul Chcp 1251
Set "FileIn=Z:\Box_In\JtoS.txt"

FOR /F "usebackq delims=" %%s In ("%FileIn%") DO (
FOR /F "usebackq tokens=3* delims= " %%a In (`Echo "%%s"^|Find /I "Содержимое папки"`) DO (
Set "Fold=%%~b"
Call Set "Fold=%%Fold:~0,-1%%"
)
FOR /F "usebackq tokens=3* delims= " %%a In (`Echo "%%s"^|Find /I "<JUNCTION>"`) DO (
Call Set "Junk=%%Fold%%\%%~b"
Call Set "Junk=%%Junk:~0,-1%%"
Call Set "Junk=%%Junk: [\??\=[%%"
FOR /F "usebackq tokens=1,2 delims=[]" %%i In (`Call Echo %%Junk%%`) DO (
rem Set "L=%%i"
rem Set "T=%%j"
rem Call Echo "%%T%%" &Call Echo "%%L%%"
Call :Rezult "%%j" "%%i"
)
)
)
pause
Exit /B

:Rezult
Echo %1
Echo %2
Exit /BНаверное, удобнее выделенными строками пользоваться внутри процедуры. Я заремил использование переменных в Echo внутри цикла - имхо, это не удобно

DJ Mogarych
27-01-2022, 17:41
Powershell:


$strNum = ((gc "D:\temp\JtoS.txt" -OutVariable txt |sls 'Содержимое папки').LineNumber|% {$_ - 1})
$strNum += $txt.count
$c = 0

$report = @()
$strNum |% {
$start = $strNum[$c]
$end = $strNum[$c+1] - 1; if ($end -eq -1) {$end = $txt.count}
$piece = ($txt)[$start..$end]
($piece) -match '<junction>' |% {
$obj = [pscustomobject]@{
t = $_ -replace '.*\\\?\?\\' -replace '\]'
l = (($piece) -match 'Содержимое папки' -replace '.*папки').trim() + '\' + `
($_ -replace '.*<junction>\s+' -replace '\s+\[.*').trim()
}
$report += $obj
}
$c = $c+1
}



$report

t l
- -
H:\Фонотека\Jazz - fusion\Baldauf Rudiger H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Baldauf Rudiger
h:\Фонотека\Jazz\Beiderbecke Leon Bix H:\Слушать\Слушать\ Инструменты\Труба (trumpet)\Beiderbecke Leon Bix
H:\Фонотека\Jazz - avant-guard\Lloyd Charles H:\Слушать\Слушать\Modern jazz\Lloyd Charles
H:\Фонотека\Jazz - smooth\Aaron Blake\Blake Aaron - Desire (2007) H:\Слушать\Слушать\Smooth\Blake Aaron - Desire (2007)
H:\Фонотека\Jazz - smooth\ Various\Club des Belugas - Swop (2008) H:\Слушать\Слушать\Smooth\Club des Belugas - Swop (2008)


Бикс Бейдербек - такое сейчас редко увидишь в фонотеке...

megaloman
27-01-2022, 18:29
HankHank, Не думаю, что хорошая идея копаться в файле. А почему бы сразу не обрабатывать вывод Dir?@Echo Off
cls
>nul Chcp 1251
Set "BoxIn=H:\"

FOR /F "usebackq delims=" %%d In (`2^>nul Dir "%BoxIn%" /AL /S /B`) DO (
FOR /F "usebackq tokens=1,2 delims=[]" %%i In (`2^>nul Dir /AL "%BoxIn%%%~nxd*.*"^|Find /I "<JUNCTION>"`) DO (
Echo.
Echo "%%d"
Set "L=%%j"
Call Set "L=%%L:\??\=%%"
Call Echo "%%L%%"
)
)
pause
Exit /BПолноценно не тестировал,

HankHank
27-01-2022, 21:05
Код для скрипта может быть проще, если использовать команду

DIR /AL /B /S H:\

Тогда получим чистые строки с полными путями к ссылкам:


H:\Слушать\Слушать\Albright Gerald
H:\Слушать\Слушать\Alex Rostotsky - Time when fish think of the past (2004)
H:\Слушать\Слушать\Dave Brubeck - Ken Burns Jazz (Columbia - Legacy Records) 2000
H:\Слушать\Слушать\Dino Saluzzi - El Encuentro (2010) [Flac]
H:\Слушать\Слушать\Modern Jazz Quartet - Live At The Lighthouse (MFSL MFCD 827) (1967)



А, еcли вызвать по ссылке FSUTIL, то получим список строк, в котором нас интересует “Print Name:” - это и будет целевой объект.

Например:

FSUTIL reparsepoint query “H:\Слушать\Слушать\Alex Rostotsky - Time when fish think of the past (2004)”


Reparse Tag Value : 0xa0000003
Tag value: Microsoft
Tag value: Name Surrogate
Tag value: Mount Point
Substitue Name offset: 0
Substitue Name length: 184
Print Name offset: 186
Print Name Length: 176
Substitute Name: \??\h:\Фонотека\Jazz\Rostotsky Alex\Alex Rostotsky - Time when fish think of the past (2004)
Print Name: h:\Фонотека\Jazz\Rostotsky Alex\Alex Rostotsky - Time when fish think of the past (2004)



Таким образом, проблемы со спецсимволами серьёзно сокращаются.

Мне кажется, при таком раскладе шаблон для CMD вполне должен прокатить.

HankHank
28-01-2022, 10:13
Не думаю, что хорошая идея копаться в файле. А почему бы сразу не обрабатывать вывод Dir? »
Идея хорошая по причине того, что вывести простыню со всеми файлами можно всего один раз.
После чего брать из файла мелкие порции и отладить скрипт. Засада ожидается с русскими символами и спецсимволами.
А уже большими частями обработать всё оставшееся безобразие.

megaloman
28-01-2022, 10:33
Идея хорошая по причине того, что вывести простыню со всеми файлами можно всего один раз.
После чего брать из файла мелкие порции и отладить скрипт. »Тут уж в огороде бузина а в Киеве дядька: отлаживаем скрипт, который удобно отлаживать, а эффективно использовать будем другой, неотлаженный.
Берите скрипт с непосредственной обработкой Dir и натравливайте его на небольшую папку. :)

HankHank
28-01-2022, 10:44
Берите скрипт с непосредственной обработкой Dir и натравливайте его на небольшую папку »
Тоже вариант.
Только обходить вручную весь диск - не лучшая идея.
Плоская "простыня" кажется удобнее.

megaloman
28-01-2022, 11:17
Только обходить вручную весь диск - не лучшая идея. »Не обходите. Укажите, для отладки, для Dir папочку, например в моём варианте:

Set "BoxIn=H:\Слушать\Слушать\Modern jazz\"
или более обьемную:
Set "BoxIn=H:\Слушать\Слушать\"

и добейтесь в отладке полного счастья.
Но отлаживать по любому надо скрипт, который собрались применять.

HankHank
28-01-2022, 15:25
У меня начальные познания о командных файлах. Но CALL-оператор, вроде, вызывает внешний комфайл или передаёт управление внутри того же файла.
Подскажите, в чём фишка употребления CALL в сочетании с другими операторами типа:

Call Set "Junk=%%Junk:~0,-1%%"
Call Echo "%%T%%" &Call Echo "%%L%%" »

?

DJ Mogarych
28-01-2022, 15:52
У меня начальные познания о командных файлах »
Переходите на Powershell тогда лучше сразу. Там решена масса проблем CMD.

megaloman
28-01-2022, 18:18
Подскажите, в чём фишка употребления CALL в сочетании с другими операторами »Дело в отложенном раскрытии переменных командной строки.
Вот примеры. Проделайте, проанализируйте. Все эти махинации нужны, чтобы в цикле можно было использовать изменяемые значения переменных.
В 111111 Call не применяли, в результате имеем значение Junk до цикла.
В 222222 используем Call для раскрытия значения переменной внутри цикла,
а в 333333 работаем с переменной Junk внутри вызываемой в цикле процедуры.
В 444444 применяем SetLocal EnableDelayedExpansion для раск для раскрытия значения переменной внутри цикла. Там переменная заключается в знаки !Junk!
При этом возможны неприятности: если в значении переменной присутствует !, то получим непредсказуеый результат.
@Echo Off
cls
Echo. &Echo ----- 111111 Без Call
Set "Junk="
For /L %%i In (100001,100000,400000) Do (
Set "Junk=%%i"
Set "Junk=%Junk:~0,-1%"
Echo i=%%i Junk="%Junk%"
)
Echo "%Junk%"

Echo. &Echo ----- 222222 C Call
Set "Junk="
For /L %%i In (100001,100000,400000) Do (
Set "Junk=%%i"
Call Set "Junk=%%Junk:~0,-1%%"
Call Echo i=%%i Junk="%%Junk%%"
)
Echo "%Junk%"

Echo. &Echo ----- 333333 C процедурой
Set "Junk="
For /L %%i In (100001,100000,400000) Do Call :MyEcho %%i
Echo "%Junk%"

Echo. &Echo ----- 444444 SetLocal EnableDelayedExpansion
SetLocal EnableDelayedExpansion
Set "Junk="
For /L %%i In (100001,100000,400000) Do (
Set "Junk=%%i"
Set "Junk=!Junk:~0,-1!"
Echo i=%%i Junk="!Junk!"
)
Echo "%Junk%"
SetLocal DisableDelayedExpansion

Pause
Exit /B

:MyEcho
Set "Junk=%1"
Set "Junk=%Junk:~0,-1%"
Echo i=%1 Junk="%Junk%"
Exit /B
Аналогичные проблемы при работе с переменными внутри If




© OSzone.net 2001-2012