Как изменить значения в текстовых файлах? - PullRequest
1 голос
/ 10 мая 2019

Я просто пытаюсь создать скрипт powershell, который изменит числовые значения в наборе текстовых файлов. Данные в текстовых файлах разделяются точкой с запятой. Значения, которые я хочу изменить, это всегда 2-й и 3-й токены в каждой строке текстового файла.

Пример строки в одном из файлов:

"Bridge_Asphalt_F";202498.396728;1104.362183;9.721280;0.000000;0.000000;1.000000;-1.299559;

Я хочу разрешить пользователю скрипта вводить значения, которые будут добавлены (или вычтены) из 2-го и 3-го значений во всех строках всех текстовых файлов в текущем каталоге.

У меня есть базовое понимание сценариев, но я часами искал, пытаясь обдумать, как это можно сделать.

Это то, что я имею до сих пор, но я уверен, что я неправильно понял несколько вещей:

$east = Read-Host 'Easting?'
$north = Read-Host 'Northing?'

Get-ChildItem  *.txt |
Foreach-Object {
    $c = ($_ | Get-Content)
    $c = $c -replace $regexB,$regexB+$east
    $c = $c -replace $regexC,$regexC+$north
    [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
}

Значения определяют местоположение объекта на карте (для игры), и я хочу иметь возможность перемещать все объекты на всей карте на определенное расстояние по осям x и y.

Ответы [ 3 ]

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

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

$offset2 = 100
$offset3 = 100

Import-Csv .\data.txt -Delimiter ';' -Header (1 .. 9) |
    ForEach-Object {
        $_.2 = ([double]$_.2) + $offset2
        $_.3 = ([double]$_.3) + $offset3

        $_
    } | ConvertTo-Csv -NoTypeInformation -Delimiter ';'  |
            Select-Object -Skip 1 |
                Add-Content .\updated.txt

Примечание :

ConvertTo-Csv окружает каждый элемент кавычками, так что в итоге вы получите что-то вроде этого:

"Bridge_Asphalt_F";"202198.396728";"1104.362183";"9.721280";"0.000000";"0.000000";"1.000000";"-1.299559"

Это может вызвать проблемы, если этого не ожидаетваша игра.Если это так, то можно выполнить дополнительную обработку конвейера.

Кроме того, в прошлом у меня были проблемы с попыткой импорта и экспорта в один и тот же файл CSV, отсюда мой вывод кодав другой файл.Попробуйте сами, и если он работает с тем же файлом, отлично, в противном случае скопируйте мой пример, затем добавьте строку, чтобы заменить существующий файл новым (например, используя Move-Item).

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

Если ваша игра не может обрабатывать значения координат в кавычках, которые вы получаете при использовании ConvertTo-Csv или Export-Csv, это должно обновить значения, оставляя кавычки выключенными:

$eastOffset  = 100
$northOffset = -200
(Get-Content 'D:\coordinates.txt') | ForEach-Object {
    $fields = $_ -split ';'
    [double]$fields[1] += $eastOffset
    [double]$fields[2] += $northOffset
    # write the updated stuff to file
    Add-Content -Path 'D:\newcoordinates.txt' -Value ($fields -join ';')
}

это содержание

"Bridge_Asphalt_F";202498.396728;1104.362183;9.721280;0.000000;0.000000;1.000000;-1.299559;
"Road_Asphalt_F";202123.396728;1104.362456;9.721280;0.000000;0.000000;1.000000;-1.299559;

станет

"Bridge_Asphalt_F";202598.396728;904.362183;9.721280;0.000000;0.000000;1.000000;-1.299559;
"Road_Asphalt_F";202223.396728;904.362456;9.721280;0.000000;0.000000;1.000000;-1.299559;
0 голосов
/ 10 мая 2019

Полагаю, это то, что вам нужно:

cls
cd C:\Users\dandraka\Desktop\test #or whereever

$eastStr = Read-Host 'Easting?'
$northStr = Read-Host 'Northing?'

# convert input to number
$east = [decimal]::Parse($eastStr)
$north = [decimal]::Parse($northStr)

# loop through files
$files = Get-ChildItem  *.txt 
$files | Foreach-Object {

    $fileName = $_.FullName # just for clarity
    Write-Host $fileName

    $newLines = New-Object System.Collections.ArrayList

    # loop through lines of each file
    $lines = Get-Content -Path $fileName
    $lines | ForEach-Object {

        $line = $_.ToString() # just for clarity
        $lineItems = $line -split ';'
        $pointName = $lineItems[0]
        $latitudeStr = $lineItems[1]
        $longitudeStr = $lineItems[2]        

        # convert to number
        $latitude = [decimal]::Parse($latitudeStr)
        $longitude = [decimal]::Parse($longitudeStr)

        Write-Host "$pointName latitude $latitude , longitude $longitude"

        # do the math
        $newLatitude = $latitude + $north
        $newLongitude = $longitude + $east

        Write-Host "$pointName new latitude $newLatitude , new longitude $newLongitude"

        # recontruct the line
        $newLine = ""
        for($i=0; $i -lt $lineItems.Count; $i++) {
            if ($i -eq 1) {  
                $newLine += "$newLatitude;"
                continue
            }
            if ($i -eq 2) {  
                $newLine += "$newLongitude;"
                continue
            }
            # this if fixes a small bug, without it there are two ; at the end of each line
            if ($lineItems[$i].Length -gt 0) {
                $newLine += "$($lineItems[$i]);"            
            }
        }
        Write-Host "Old line $line"
        Write-Host "New line $newLine"
        $newLines.Add($newLine) | Out-Null
    }

    # write file
    $newFilename = $fileName.Replace(".txt", ".dat")
    [System.IO.File]::WriteAllLines($newFilename, $newLines)
    Write-Host "File $newFilename written"
}

Несколько вещей, на которые стоит обратить внимание:

  1. Поскольку вы упоминаете, что вы начинаете с powershell, я написал код более многословно, чем, скажем, для опытного разработчика. Но это на самом деле не больно.

  2. По той же причине код является неоптимальным по назначению (облегчает чтение кода). Но для лучшей производительности и больших файлов (скажем, несколько десятков МБ или более) вам нужно действовать по-другому, например, избегайте строк и используйте вместо этого строитель строк.

  3. Очевидно, что вы можете закомментировать все операторы Write-Host, они существуют только для того, чтобы убедиться, что код работает правильно.

Надеюсь, это поможет!

Jim

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...