У меня есть текстовые файлы, содержащие
Firstname: xxx
Lastname: yyy
Login: abcd
Там есть много других записей для других определений, но все в том же формате header: data
Я хотел бы использовать массив в PowerShell для их чтения и хотел бы сделать
$array.firstname
$array.Login
чтобы получить мне данные.
Можно ли это сделать?
В настоящее время мы используем длинное регулярное выражение для вывода данных, но оно становится громоздким, и мы хотели бы его упростить.
Пожалуйста, добавьте минимальный воспроизводимый пример к вашему вопросу. В качестве общего (нерегулярного) решения вы можете использовать ConvertFrom-String с собственным шаблоном.
Я хотел бы использовать массив в PowerShell для их чтения и хотел бы сделать
Массивы — это просто контейнеры фиксированного размера, кратные чему-то, сами по себе они ничего не делают.
Если вам нужна вещь, имеющая произвольные именованные свойства, такие как firstname
или login
, вам нужен собственный объект.
Вы можете использовать оператор регулярного выражения -match
для идентификации и извлечения метки и значения в каждой строке, например:
$filePath = 'C:\path\to\file.txt'
# create an ordered dictionary to temporarily hold the label-value pairs
$properties = [ordered]@{}
# read the file into memory line-by-line
Get-Content $filePath |ForEach-Object {
# test whether the line matches the `label: value` format
if ($_ -match '^([^:]+):\s*(.*)$') {
# ... and if so, extract the values matched by the capture groups
$properties[$Matches[1]] = $Matches[2]
}
}
# finally convert the ordered dictionary to an object
$myObject = [pscustomobject]$properties
$myObject
теперь содержит объект со свойствами, названными в честь меток заголовков, найденных в файле, поэтому теперь вы можете ссылаться на $myObject.Login
и т. д.
Если вы хотите вообще избежать регулярных выражений, используйте String.Split() вместо -match
+$Matches
:
# read the file into memory line-by-line
Get-Content $filePath |ForEach-Object {
# test whether the line has a `:`
if ($_ -like '*:*') {
$label,$value = $_.Split(':', 2) |ForEach-Object Trim
$properties[$label] = $value
}
}
Это именно то, что мы используем, и я хотел бы отойти от регулярных выражений
@BillySmith Я думал, ты хочешь отойти от громоздкого шаблона регулярных выражений - ^([^:]+):\s*(.*)$
слишком много?
Действительно, этот код string.Split() получает индекс Cannot в нулевой массив.
@BillySmith, второй пример - это частичный фрагмент, вам все равно нужно заранее определить $properties = [ordered]@{}
Привет, Матиас! Я ценю твою помощь, теперь я получаю все объекты в $properties.Firstname.
Возможно, вы случайно добавили параметр -Raw при вызове Get-Content
?
Да, -raw используется get-content, и если я загружаю файл в Notepad++, я вижу CRLF в конце каждой строки. Удалил -raw и все заработало
В Powershell 5.1 вы не можете указать разделитель. Он ожидает =
в качестве разделителя, поэтому сначала замените :
на =
. Если в строке несколько :
, мы заменим только первое вхождение, используя регулярные выражения и группы захвата.
$hashtable = (Get-Content .\data.txt -Raw) -replace '(?m)^(.*?):(.*$)', '$1=$2' | ConvertFrom-StringData
$hashtable.Login
$hashtable.Firstname
$hashtable.Lastname
В PowerShell 7+ был введен параметр -Delimiter
.
$hashtable = Get-Content .\data.txt -Raw | ConvertFrom-StringData -Delimiter ':'
$hashtable.Login
$hashtable.Firstname
$hashtable.Lastname
Содержит ли каждый файл только уникальные значения заголовков (например, только 1 строку входа в систему на файл)?