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

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   AutoIt (http://forum.oszone.net/forumdisplay.php?f=103)
-   -   [решено] Функция для добавления текста в файл с учётом нумерации, на примере Scenery.cfg (http://forum.oszone.net/showthread.php?t=192902)

twister777 03-12-2010 06:58 1557226

Функция для добавления текста в файл с учётом нумерации, на примере Scenery.cfg
 
Добрый день.

Многие энтузиасты Flight Simulator X часто сталкиваются с потребностью добавлять новые текстовые записи
в конфигурационный файл симулятора.

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

Задача:

Есть готовый текстовый файл по пути c:\Users\All Users\Microsoft\FSX\
с именем Scenery.CFG

Имеет структуру:

Код:


[General]
Title=FS9 World Scenery
Description=FS9 Scenery Data
Clean_on_Exit=TRUE

[Area.001]
Title=Default Terrain
Local=Scenery\World
Texture_ID=1
Layer=1
Active=TRUE
Required=TRUE

[Area.002]
Title=Default Scenery
Local=Scenery\BASE
Layer=2
Active=TRUE
Required=TRUE

..... СОКРАТИМ ДЛЯ УДОБСТВА

[Area.127]
Title=Menorca X Ground
Local=Aerosoft\Menorca X Ground
Active=TRUE
Layer=124
Required=FALSE

[Area.128]
Title=Menorca X SC
Local=Aerosoft\Menorca X SC
Active=TRUE
Layer=125
Required=FALSE

Функции передается строка Title (название)и строка Local(относительный путь к папке).
Функция сама находит максимальное значение числа в строчках Area и Layer (по всему файлу),
после чего увеличивает Area на еденицу и Layer на еденицу.
Записывает результирующий кусочек текста в конец файла.

Результатом ее работы должно стать добавление такого кусочка текста в исходный файл c примером:

Код:

[Area.129]
Title=Ibiza X Ground
Local=Aerosoft\Ibiza X Ground
Active=TRUE
Layer=126
Required=FALSE

Собственно всё.
Заранее спасибо за потраченное вами время и участие.

gregaz 03-12-2010 13:04 1557437

Так ? :
Код:

;$sFilePath="c:\Users\All Users\Microsoft\FSX\Scenery.CFG"
$sFilePath=@ScriptDir & "\1.txt"

$sText=FileRead($sFilePath)
MsgBox(0,'$sText',$sText)

$sPattern="(?s).+(\[.+?)"
$sFind=StringRegExpReplace($sText,$sPattern,"\1")

$sPattern="(.+[=.])(.+)"
$aFind=StringRegExp($sFind,$sPattern,3)

$sRet=''
For $i=0 To UBound($aFind)-2 Step 2
        If $i=0 Or  $i=8 Then $aFind[$i+1]+=1
        If $i=0 Then $aFind[$i+1]&= "]"
        $sRet&= $aFind[$i] & $aFind[$i+1] & @LF
Next

ConsoleWrite($sRet & @LF)

$hFile=FileOpen($sFilePath,1)
FileWrite($hFile,$sRet)
FileClose($hFile)


twister777 03-12-2010 13:31 1557456

Я не очень разбираюсь в синтаксисе AutoIt...

А где здесь переменная в которую задавать
Title=Ibiza X Ground
Local=Aerosoft\Ibiza X Ground
и их вывод в результирующий файл.

и где вывод вот таких строчек
Active=TRUE
Required=FALSE

?

madmasles 03-12-2010 13:46 1557465

twister777,
Как я понял, файл Scenery.CFG имеет структуру ini-файла. Тогда можно так попробовать:
Код:

Opt('MustDeclareVars', 1)

Global $sLocalNew = 'Aerosoft\Ibiza X Ground' ;новый Local
Global $sTitleNew = 'Island of Ibiza' ;новый Title
Global $sFile = @ScriptDir & '\Scenery.CFG';поменяйте на нужный Вам полный путь к файлу
Global $sRes
$sRes = _AddNewSection($sLocalNew, $sTitleNew, $sFile)
If @error Then
    MsgBox(16, 'Error', 'Error')
Else
    MsgBox(64, 'OK', 'Add new section: [Area.' & @extended & ']' & @CRLF & _
            'with new Layer: ' & $sRes)
EndIf

Func _AddNewSection($sLocal, $sTitle, $sFileCFG)
    Local $hFile, $aSectionNames, $iTempSectionNumber, $iTempLayerNumber, $iNumberSectionMax = 0, _
            $iNumberLayerMax = 0
    Local $sNewSection = 'Area.'
    Local $sComment = @CRLF & ';Next section add ' & @MDAY & '.' & @MON & '.' & @YEAR & ' ' & _
            @HOUR & ':' & @MIN
    Local $aNewData[5][2] = [['Title', $sTitle],['Local', $sLocal],['Active', 'TRUE'], _
            ['Layer'],['Required', 'FALSE']]
    If Not FileExists($sFileCFG) Then Return SetError(1)
    If Not $sTitle Then Return SetError(1)
    $hFile = FileOpen($sFileCFG, 1)
    If $hFile = -1 Then Return SetError(1)
    If FileWrite($hFile, $sComment) = 0 Then Return SetError(1)
    FileClose($hFile)
    $aSectionNames = IniReadSectionNames($sFileCFG)
    If @error Then Return SetError(1)
    For $i = 1 To $aSectionNames[0]
        $iTempSectionNumber = Number(StringRegExpReplace($aSectionNames[$i], '[^0-9]', ''))
        If $iTempSectionNumber > $iNumberSectionMax Then
            $iNumberSectionMax = $iTempSectionNumber
        EndIf
        $iTempLayerNumber = Number(IniRead($sFileCFG, $aSectionNames[$i], $aNewData[3][0], 0))
        If $iTempLayerNumber > $iNumberLayerMax Then
            $iNumberLayerMax = $iTempLayerNumber
        EndIf
    Next
    $iNumberLayerMax = $iNumberLayerMax + 1
    $iNumberSectionMax = StringFormat('%03d', $iNumberSectionMax + 1)
    $sNewSection = $sNewSection & $iNumberSectionMax
    $aNewData[3][1] = $iNumberLayerMax
    If Not IniWriteSection($sFileCFG, $sNewSection, $aNewData, 0) Then Return SetError(1)
    Return SetError(0, $iNumberSectionMax, $iNumberLayerMax)
EndFunc  ;==>_AddNewSection


twister777 03-12-2010 14:22 1557491

madmasles,
Да, это похоже на ini-файл.
Вот это, мне кажется, то, что нужно, жаль я сейчас на работе - нет возможности скомпилировать и проверить работоспособность (((

Я хочу уточнить.

-------------------------------------------------------------------
при выводе:

[Area.129] ; числовое значение меняется, а все буквы и скобки неизменны
Title=Ibiza X Ground ; 'Title=' неизменные символы , 'Ibiza X Ground' задаётся в Global
Local=Aerosoft\Ibiza X Ground ; символы после знака равно это путь, он НИКАК не связан с Title, он должен задаваться в Global,а вашем варианте они связаны
Active=TRUE ; эта строчка всегда неизменна
Layer=126 ; числовое значение меняется, а все буквы и '=' неизменны
Required=FALSE ; эта строчка всегда неизменна

-----------------------------------------------------------------------------------------------

P.S. Я даже не ожидал, что так быстро найдётся почти готовое решение, спасибо.

gregaz 03-12-2010 14:49 1557518

Цитата:

Цитата twister777
Я не очень разбираюсь в синтаксисе AutoIt...
А где здесь переменная в которую задавать
Title=Ibiza X Ground
Local=Aerosoft\Ibiza X Ground
и их вывод в результирующий файл.
и где вывод вот таких строчек
Active=TRUE
Required=FALSE »

;Тогда так для наглядности :

Код:

#include<Array.au3>
;$sFilePath="c:\Users\All Users\Microsoft\FSX\Scenery.CFG"
$sFilePath=@ScriptDir & "\1.txt"
;Чтение всего файла
$sText=FileRead($sFilePath)
MsgBox(0,'$sText',$sText)

; Получение текста последней ячейки (имеется ввиду , что последняя ячейка и есть Max)
$sPattern="(?s).+(\[.+?)"
$sFind=StringRegExpReplace($sText,$sPattern,"\1")
MsgBox(0,'$sFind',$sFind)
ConsoleWrite("Найденный текст ячейки : " &  @LF & $sFind & @LF)

; Получение массива всех строк последней ячейки
$sPattern="(.+[=.])(.+)"
$aFind=StringRegExp($sFind,$sPattern,3)
_ArrayDisplay($aFind,'$aFind')

; Получение нового текста ячейки
$sRet=''
For $i=0 To UBound($aFind)-2 Step 2
        If $i=0 Or  $i=8 Then $aFind[$i+1]+=1 ; Увеличение числа для строк 1 и 5 в ячейке
        If $i=0 Then $aFind[$i+1]&= "]"; Добавление "]" к строке 1 ячейки
        ; Остальные значения строк не меняются ( остаются прежними)
        $sRet &= $aFind[$i] & $aFind[$i+1] & @LF ; объединение элементов массива в строку текста
Next
MsgBox(0,'$sRet',$sRet) : Записываемый текст
ConsoleWrite("Нновый текст ячейки : " &  @LF & $sRet & @LF)

; Запись нового текста ячейки в конец файла
$hFile=FileOpen($sFilePath,1)
FileWrite($hFile,$sRet)
FileClose($hFile)


twister777 03-12-2010 15:12 1557533

gregaz,
Строчка вывода 2 и 3 должна где-то задаваться - там прописываются пути и названия, они разные, в этом смысл автоматизации.
http://forum.oszone.net/post-1557491-5.html

Вам тоже спасибо за вариант решения.

После 20.00 МСК попробую оба варианта дома на практике.

madmasles 03-12-2010 15:25 1557540

Цитата:

Цитата twister777
[Area.129] ; числовое значение меняется, а все буквы и скобки неизменны
Title=Ibiza X Ground ; 'Title=' неизменные символы , 'Ibiza X Ground' задаётся в Global »

Да.
Цитата:

Цитата twister777
Active=TRUE ; эта строчка всегда неизменна
Layer=126 ; числовое значение меняется, а все буквы и '=' неизменны
Required=FALSE ; эта строчка всегда неизменна »

Да.
Цитата:

Цитата twister777
Local=Aerosoft\Ibiza X Ground ; символы после знака равно это путь, он НИКАК не связан с Title, он должен задаваться в Global,а вашем варианте они связаны »

Здесь мне не совсем понятно.
Title=Ibiza X Ground связаны или нет с Local=Aerosoft\Ibiza X Ground?
Путь к файлу Scenery.CFG и его имя постоянны или нет?

twister777 03-12-2010 16:00 1557562

madmasles,
Цитата:

Путь к файлу Scenery.CFG и его имя постоянны или нет?
Постоянный путь и постоянное имя файла.

Цитата:

Title=Ibiza X Ground связаны или нет с Local=Aerosoft\Ibiza X Ground?
Не связаны. Просто так совпало на примере, сорри.

Нужно в функцию передать Title= (например 'Island of Ibiza') и передать путь к сценарию Local= (например 'Aerosoft\Ibiza X Ground')

----------------------------------------------------------------------------------------------------
функция, скорее всего, будет вызываться несколько раз последовательно (будут добавляться несколько разных итоговых секций за один запуск главного скрипта)

madmasles 03-12-2010 18:47 1557641

twister777,
Если я все правильно понял, то сейчас функция должна работать как надо. Я код в своем посте поправил. Можно еще с окном типа
Код:

#include <GUIConstantsEx.au3>
#include <StaticConstants.au3>
#include <WindowsConstants.au3>

Opt('TrayMenuMode', 1)

$sFile = @ScriptDir & '\Scenery.CFG'

#region ### START Koda GUI section ### Form=
$hGui = GUICreate('Редактор Scenery.CFG', 300, 205, -1, -1)
GUICtrlCreateLabel('Введите Title', 10, 5, 280, 17, $SS_CENTER)
GUICtrlCreateLabel('Введите Local', 10, 50, 280, 17, $SS_CENTER)
GUICtrlCreateLabel('Путь к файлу Scenery.CFG', 10, 95, 280, 17, $SS_CENTER)
$LabelResult = GUICtrlCreateLabel('', 0, 185, 300, 20)
$InputTitle = GUICtrlCreateInput('', 10, 25, 280, 20)
$InputLocal = GUICtrlCreateInput('', 10, 70, 280, 20)
$InputCFG = GUICtrlCreateInput($sFile, 10, 115, 280, 20)
$ButtonGo = GUICtrlCreateButton('Редактировать', 40, 145, 90, 30)
$ButtonOpen = GUICtrlCreateButton('Открыть', 170, 145, 90, 30)

GUISetState()
#endregion ### END Koda GUI section ###

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $ButtonOpen
            $sFile = GUICtrlRead($InputCFG)
            If FileExists($sFile) Then
                Run('NotePad ' & $sFile)
            Else
                GUICtrlSetData($LabelResult, 'ERROR: Файл не найден.')
            EndIf
        Case $ButtonGo
            $sTitleNew = GUICtrlRead($InputTitle)
            $sLocalNew = GUICtrlRead($InputLocal)
            $sFile = GUICtrlRead($InputCFG)
            If Not $sTitleNew Or Not $sLocalNew Or Not $sFile Then
                GUICtrlSetData($LabelResult, 'Вы ввели не все данные.')
            Else
                $sRes = _AddNewSection($sLocalNew, $sTitleNew, $sFile)
                If Not @error Then
                    GUICtrlSetData($LabelResult, 'OK: Новая секция: [Area.' & @extended & ']' _
                            & 'с новым Layer: ' & $sRes)
                    GUICtrlSetData($InputTitle, '')
                    GUICtrlSetData($InputLocal, '')
                Else
                    GUICtrlSetData($LabelResult, 'ERROR: Произошла ошибка редактирования.')
                EndIf
            EndIf
    EndSwitch
WEnd

;тут функцию _AddNewSection($sLocal, $sTitle, $sFileCFG) добавить.


twister777 03-12-2010 22:10 1557787

madmasles,
Проверил, функция работает отлично.
Если не сложно, поправьте мою ошибку - сейчас перепроверил структуру недоглядел.
При выводе строчку Layer выводить после Local, затем Active, затем Required

[Area.129]
Title=Ibiza X Ground
Local=Aerosoft\Ibiza X Ground
Layer=126
Active=TRUE
Required=FALSE

Огромное вам спасибо!!!!

Если интересно будет что-нибудь по теме симуляторов - смело пишите: williamfoxtrot[@]gmail[dot]com

madmasles 03-12-2010 22:33 1557796

twister777,
Поправил:
читать дальше »
Код:

Opt('MustDeclareVars', 1)

Global $sLocalNew = 'Aerosoft\Ibiza X Ground' ;новый Local
Global $sTitleNew = 'Island of Ibiza' ;новый Title
Global $sFile = @ScriptDir & '\Scenery.CFG';поменяйте на нужный Вам полный путь к файлу
Global $sRes
$sRes = _AddNewSection($sLocalNew, $sTitleNew, $sFile)
If @error Then
    MsgBox(16, 'Error', 'Error')
Else
    MsgBox(64, 'OK', 'Add new section: [Area.' & @extended & ']' & @CRLF & _
            'with new Layer: ' & $sRes)
EndIf

Func _AddNewSection($sLocal, $sTitle, $sFileCFG)
    Local $hFile, $aSectionNames, $iTempSectionNumber, $iTempLayerNumber, $iNumberSectionMax = 0, _
            $iNumberLayerMax = 0
    Local $sNewSection = 'Area.'
    Local $sComment = @CRLF & ';Next section add ' & @MDAY & '.' & @MON & '.' & @YEAR & ' ' & _
            @HOUR & ':' & @MIN
    Local $aNewData[5][2] = [['Title', $sTitle],['Local', $sLocal],['Layer'], _
            ['Active', 'TRUE'],['Required', 'FALSE']]
    If Not FileExists($sFileCFG) Then Return SetError(1)
    If Not $sTitle Or Not $sLocal Then Return SetError(1)
    $hFile = FileOpen($sFileCFG, 1)
    If $hFile = -1 Then Return SetError(1)
    If FileWrite($hFile, $sComment) = 0 Then Return SetError(1)
    FileClose($hFile)
    $aSectionNames = IniReadSectionNames($sFileCFG)
    If @error Then Return SetError(1)
    For $i = 1 To $aSectionNames[0]
        $iTempSectionNumber = Number(StringRegExpReplace($aSectionNames[$i], '[^0-9]', ''))
        If $iTempSectionNumber > $iNumberSectionMax Then
            $iNumberSectionMax = $iTempSectionNumber
        EndIf
        $iTempLayerNumber = Number(IniRead($sFileCFG, $aSectionNames[$i], $aNewData[2][0], 0))
        If $iTempLayerNumber > $iNumberLayerMax Then
            $iNumberLayerMax = $iTempLayerNumber
        EndIf
    Next
    $iNumberLayerMax = $iNumberLayerMax + 1
    $iNumberSectionMax = StringFormat('%03d', $iNumberSectionMax + 1)
    $sNewSection = $sNewSection & $iNumberSectionMax
    $aNewData[2][1] = $iNumberLayerMax
    If Not IniWriteSection($sFileCFG, $sNewSection, $aNewData, 0) Then Return SetError(1)
    Return SetError(0, $iNumberSectionMax, $iNumberLayerMax)
EndFunc  ;==>_AddNewSection


Есть нюанс. Если нет ни одной секции [Area.***], то будет добавлена секция [Area.001] и значение Layer=1. Можно это значение изменить. Можно, наверное, еще задать какие-то условия на проверку валидности Title и Local.

twister777 04-12-2010 04:56 1557928

madmasles,
Не стоит. Area.001 по Area.120 уже есть с самого начала установки симулятора.
Это стандартные сценарии.
Мы добавляем хорошие, красивые - просто разработчикам очень часто не хватает квалификации написать
утилитку для их регистрации.

kaster 04-12-2010 05:29 1557929

Цитата:

Цитата twister777
просто разработчикам очень часто не хватает квалификации »

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

twister777 04-12-2010 09:25 1557965

kaster,
читать дальше »
FSX - это большой конструктор.
Разные разработчики из разных стран используя FSX SDK пишут дополнения.
Сценарии, летательные аппараты. Кто-то на коммерческой основе, кто-то нет.
И многим таки не хватает рук написать такой патчер, хотя скажем в фотосценариях они разбираются неплохо.


Время: 16:06.

Время: 16:06.
© OSzone.net 2001-