Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   Изменение строк в файле (http://forum.oszone.net/showthread.php?t=335228)

Nikugorsk 07-06-2018 15:32 2817270

Изменение строк в файле
 
Добрый день! Решил усложнить себе жизнь и начать оптимизировать некоторые процессы. Поэтому буду премного благодарен за ответ с комментариями, что где и почему пишем) Задача: в папке сложены Файлы 1, 2, 3... 1000. Формат txt. В этих файлах есть текст. Во всех разный. При этом есть строка (чаще первая) в которой написано «ааа_1#0», где 1 это число которое необходимо оставить, а все остальное надо (что в ковычках) надо удалить. Как это сделать через исполнительный файл, ибо файликов таких очень много??? Количество символов в ковычках всегда разное. Нужная комбинации всегда окружена _ и #

Iska 07-06-2018 15:41 2817271

Nikugorsk, упаковываете несколько таких файлов в архив, который прилагаете к сообщению. Дальше смотрим.

Nikugorsk 07-06-2018 16:42 2817284

Вложений: 2
Цитата:

Цитата Iska (Сообщение 2817271)
Nikugorsk, упаковываете несколько таких файлов в архив, который прилагаете к сообщению. Дальше смотрим.

Приложил

alpap 07-06-2018 17:43 2817296

Nikugorsk,
нужны файлы с разным содержимым или если знаете неплохо содержимое, есть ли в файле строка(и) с похожим содержимым кроме этой строки: 7,2 "Центр_1664#0", т.е если искать по символу _ или # или обеим или по кавычкам - гарантированно будет найдена только одна эта строка?

Iska 07-06-2018 17:53 2817298

И ещё, к словам коллеги: случайно ли то, что искомые цифры в файле совпадают с именем файла?

Iska 07-06-2018 18:31 2817305

На WSH:
Скрытый текст
Код:

Option Explicit

Dim strSourceFolder

Dim objFSO
Dim objFile

Dim objRegExp
Dim strContent

If WScript.Arguments.Count = 1 Then
        strSourceFolder = WScript.Arguments.Item(0)
       
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        If objFSO.FolderExists(strSourceFolder) Then
                Set objRegExp = WScript.CreateObject("VBScript.RegExp")
               
                With objRegExp
                        .Pattern    = "^(.+ "")(?:.+_)(\d+)(?:#)(.+"")$"
                        .Global    = True
                        .MultiLine  = True
                End With
               
                For Each objFile In objFSO.GetFolder(strSourceFolder).Files
                        If StrComp(objFSO.GetExtensionName(objFile.Name), "txt", 0) = 0 Then
                                With objFSO.OpenTextFile(objFile.Path)
                                        strContent = .ReadAll()
                                        .Close
                                End With
                               
                                If objRegExp.Test(strContent) Then
                                        objFSO.CopyFile objFile.Name, objFSO.GetBaseName(objFile.Name) & ".bak", True
                                       
                                        With objFSO.CreateTextFile(objFile.Name, True)
                                                .Write objRegExp.Replace(strContent, "$1$2$3")
                                                .Close
                                        End With
                                Else
                                        ' Nothing to do
                                End If
                        Else
                                ' Nothing to do
                        End If
                Next
               
                Set objRegExp = Nothing
        Else
                WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
                WScript.Quit 2
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: cscript.exe //nologo """ & WScript.ScriptName & """ <Source folder>"
        WScript.Quit 1
End If

WScript.Quit 0


Исходная папка указывается аргументом скрипта (также можно просто перетащить папку на скрипт в Проводнике). Будут обработаны все *.txt файлы из указанной папки. При нахождении шаблона в содержимом текстового файла и последующей замене делается резервная копия исходного файла с расширением .bak.

Согласно изложенным Вами выше правилам поиска и замены в выложенных для примера файлах произойдут следующие замены — в 1657.txt:
Код:

11,2 "Центр_1657#0"
на:
Код:

11,2 "16570"
и в 1664.txt:
Код:

7,2 "Центр_1664#0"
на:
Код:

7,2 "16640"

Nikugorsk 07-06-2018 20:11 2817321

Цитата:

Цитата alpap (Сообщение 2817296)
Nikugorsk,
нужны файлы с разным содержимым или если знаете неплохо содержимое, есть ли в файле строка(и) с похожим содержимым кроме этой строки: 7,2 "Центр_1664#0", т.е если искать по символу _ или # или обеим или по кавычкам - гарантированно будет найдена только одна эта строка?


Да, гарантированно найдётся только эта строка. По любому из 3х признаков.

Цитата:

Цитата Iska (Сообщение 2817305)
На WSH:
Скрытый текст
Код:

Option Explicit

Dim strSourceFolder

Dim objFSO
Dim objFile

Dim objRegExp
Dim strContent

If WScript.Arguments.Count = 1 Then
        strSourceFolder = WScript.Arguments.Item(0)
       
        Set objFSO = WScript.CreateObject("Scripting.FileSystemObject")
       
        If objFSO.FolderExists(strSourceFolder) Then
                Set objRegExp = WScript.CreateObject("VBScript.RegExp")
               
                With objRegExp
                        .Pattern    = "^(.+ "")(?:.+_)(\d+)(?:#)(.+"")$"
                        .Global    = True
                        .MultiLine  = True
                End With
               
                For Each objFile In objFSO.GetFolder(strSourceFolder).Files
                        If StrComp(objFSO.GetExtensionName(objFile.Name), "txt", 0) = 0 Then
                                With objFSO.OpenTextFile(objFile.Path)
                                        strContent = .ReadAll()
                                        .Close
                                End With
                               
                                If objRegExp.Test(strContent) Then
                                        objFSO.CopyFile objFile.Name, objFSO.GetBaseName(objFile.Name) & ".bak", True
                                       
                                        With objFSO.CreateTextFile(objFile.Name, True)
                                                .Write objRegExp.Replace(strContent, "$1$2$3")
                                                .Close
                                        End With
                                Else
                                        ' Nothing to do
                                End If
                        Else
                                ' Nothing to do
                        End If
                Next
               
                Set objRegExp = Nothing
        Else
                WScript.Echo "Can't find source folder [" & strSourceFolder & "]."
                WScript.Quit 2
        End If
       
        Set objFSO = Nothing
Else
        WScript.Echo "Usage: cscript.exe //nologo """ & WScript.ScriptName & """ <Source folder>"
        WScript.Quit 1
End If

WScript.Quit 0


Исходная папка указывается аргументом скрипта (также можно просто перетащить папку на скрипт в Проводнике). Будут обработаны все *.txt файлы из указанной папки. При нахождении шаблона в содержимом текстового файла и последующей замене делается резервная копия исходного файла с расширением .bak.

Согласно изложенным Вами выше правилам поиска и замены в выложенных для примера файлах произойдут следующие замены — в 1657.txt:
Код:

11,2 "Центр_1657#0"
на:
Код:

11,2 "16570"
и в 1664.txt:
Код:

7,2 "Центр_1664#0"
на:
Код:

7,2 "16640"

А как 0 в конце убрать? Должен остаться только 1657 и 1664

Цитата:

Цитата Iska (Сообщение 2817298)
И ещё, к словам коллеги: случайно ли то, что искомые цифры в файле совпадают с именем файла?

Это частный случай. Для примера

Iska 07-06-2018 20:18 2817327

Цитата:

Цитата Nikugorsk
А как 0 в конце убрать? Должен остаться только 1657 и 1664 »

Тогда замените строку:
Код:

                        .Pattern    = "^(.+ "")(?:.+_)(\d+)(?:#)(.+"")$"
на:
Код:

                        .Pattern    = "^(.+ "")(?:.+_)(\d+)(?:#.+)("")$"
Цитата:

Цитата Nikugorsk
Это частный случай. Для примера »

Ясно.

YuS_2 07-06-2018 20:29 2817336

Цитата:

Цитата Nikugorsk
Как это сделать через исполнительный файл, ибо файликов таких очень много??? »

powershell
script.ps1
Код:

dir *.txt -file|%{
        (gc $_.fullname -enc default) -replace '(?<=\")[^_]*_|#[^"]*(?=\")'|`
        set-content ($_.fullname) -enc default
}

Для запуска скрипта:
run.bat
Код:

@echo off
echo.Поехали
powershell -ex bypass .\script.ps1
echo.Приехали
pause


Nikugorsk 08-06-2018 07:08 2817366

Вложений: 1
Цитата:

Цитата YuS_2 (Сообщение 2817336)
Цитата:

Цитата Nikugorsk
Как это сделать через исполнительный файл, ибо файликов таких очень много??? »

powershell
script.ps1
Код:

dir *.txt -file|%{
        (gc $_.fullname -enc default) -replace '(?<=\")[^_]*_|#[^"]*(?=\")'|`
        set-content ($_.fullname) -enc default
}

Для запуска скрипта:
run.bat
Код:

@echo off
echo.Поехали
powershell -ex bypass .\script.ps1
echo.Приехали
pause


Не получается

YuS_2 08-06-2018 07:25 2817367

Цитата:

Цитата Nikugorsk
Не получается »

Если Win XP, то:
Код:

dir *.txt|where{!$_.psiscontainer}|%{
        (gc $_.fullname) -replace '(?<=\")[^_]*_|#[^"]*(?=\")'|`
        set-content ($_.fullname)
}

если новее, то лучше обновить PoSh до актуальной версии...

megaloman 08-06-2018 16:39 2817469

Nikugorsk, Я не проверял код от Iska, уверен, он рабочий.
Вот еще вариант исполнимого vbs-скрипта.
Код:

InBox = "Z:\Box_In"                ' Папка с файлами
InExt = "txt"                      ' Расширение файлов для обработки
' --------------------------------

Set WArg = WScript.Arguments
If Not WArg.Count = 0 Then InBox = WArg.Item(0)

Set FSO = CreateObject("Scripting.FileSystemObject")
On Error Resume Next
Set InDir = FSO.GetFolder(InBox)
If Err.Number <> 0 Then
    MsgBox "Ошибка при открытии  " + CStr(Err.Number) + vbCrLf + vbCrLf + InBox + vbCrLf + vbCrLf + Err.Description
    WScript.Quit 2
End If

BakBox = InDir + "\" + Replace(Replace(CStr(Now), ":", "-"), "/", ".") + ".bak"
FSO.CreateFolder (BakBox)
If Err.Number <> 0 Then
    MsgBox "Ошибка при создании  " + CStr(Err.Number) + vbCrLf + vbCrLf + BakBox + vbCrLf + vbCrLf + Err.Description
    WScript.Quit 2
End If
On Error GoTo 0

Set AllFiles = InDir.Files

N = 0
For Each iFile In AllFiles      ' Цикл по файлам в папке (как вариант решения)
    If UCase(FSO.GetExtensionName(iFile)) = UCase(InExt) Then
        With FSO.OpenTextFile(iFile, 1, False)
            AllTxt = .ReadAll
            .Close
        End With
        Do
            i1 = InStr(1, AllTxt, """")
            If i1 = 0 Then Exit Do
            i2 = InStr(i1, AllTxt, "_")
            If i2 = 0 Then Exit Do
            i3 = InStr(i2, AllTxt, "#")
            If i3 = 0 Then Exit Do
            i4 = InStr(i3, AllTxt, """")
            If i4 = 0 Then Exit Do
       
            ii = InDir + "\" + iFile.Name
            i = FSO.MoveFile(iFile, BakBox + "\" + CStr(iFile.Name))
       
            With FSO.CreateTextFile(ii, True)
                .Write Mid(AllTxt, 1, i1) + Mid(AllTxt, i2 + 1, i3 - i2 - 1) + Mid(AllTxt, i4)
                .Close
            End With
            N = N + 1
        Loop While False
    End If
Next

If N = 0 Then
    MsgBox "В папке" + vbCrLf + vbCrLf + InDir + vbCrLf + vbCrLf + "файлы для обработки не найдены"
    FSO.DeleteFolder BakBox, True
    WScript.Quit 1
Else
    Msg = "В папке" + vbCrLf + InDir + vbCrLf + "обработано " + CStr(N) + " файлов"
    MsgBox Msg + vbCrLf + vbCrLf + "исходные файлы в папке" + vbCrLf + BakBox
    WScript.Quit 0
End If

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

YuS_2, Помнится, WSH в Win XP уже был, и даже для него что-то дополнительно доустанавливать уже не нужно.

Iska 08-06-2018 18:10 2817486

Цитата:

Цитата megaloman
Я не проверял код от Iska, уверен, он рабочий. »

Я на это только надеюсь, поскольку работа регулярных выражений очень сильно завязано на предположения о конкретном содержимом искомого :).

Цитата:

Цитата megaloman
YuS_2, Помнится, WSH в Win XP уже был, и даже для него что-то дополнительно доустанавливать уже не нужно. »

Так он же предлагает не WSH, а PoSH.

YuS_2 08-06-2018 18:32 2817494

Цитата:

Цитата megaloman
Помнится, WSH в Win XP уже был, и даже для него что-то дополнительно доустанавливать уже не нужно. »

Это да, powershell в XP надо установить и новее v2.0 туда не впихнуть, но в читабельности и краткости скриптов, а в некоторых случаях и просто функциональных возможностях, это не сравнимые вещи... просто взгляните на код - три командлета (по сути одна строка) делают то, что на wsh выглядит уже достаточно объемно и скорее всего, новичка оттолкнет от изучения...
А вообще, если будет больше вариантов решений той или иной задачи, разве это плохо?
Что из этого разнообразия выбрать, решит сам ТС, да и другим, столкнувшимся с аналогичной проблемой, может пригодиться...

Цитата:

Цитата Iska
Так он же предлагает не WSH, а PoSH. »

Да, о том и речь, увы, в XP нет предустановленного PoSh


Время: 20:03.

Время: 20:03.
© OSzone.net 2001-