#string #powershell #txt
#строка #powershell #txt
Вопрос:
Как я могу проверить, есть ли значение «данные» между моими двумя другими «значениями», зная, что количество строк, разделяющих их, не является регулярным и что последние «данные» не имеют «значения» после него?
values
xxx
xxx
data
xxx
values
xxx
xxx
values
xxx
data
values
xxx
data
xxx
Все, что у меня есть, это:
if (xxx) {
xxx | Add-Content -Path $DATA
} else {
Add-Content -Path $DATA -Value 'N/A'
}
И в итоге я хотел бы получить результат :
data
N/A
data
data
Ответ №1:
Вам нужно будет читать строки одну за другой и отслеживать 1) когда вы видите values
строку и 2) когда вы видите data
строку.
Я предпочитаю switch
операторы для такого нисходящего синтаксического анализа:
# In real life you would probably read from a file on disk, ie.
# $data = Get-Content somefile.txt
$data = -split 'values xxx xxx data xxx values xxx xxx values xxx data values xxx data xxx'
# Use this to keep track of whether the first "values" line has been observed
$inValues = $false
# Use this to keep track of whether a "data" line has been observed since last "values" line
$hasData = $false
switch($data)
{
'values' {
# don't output anything the first time we see `values`
if($inValues){
if($hasData){
'data'
} else {
'N/A'
}
}
$inValues = $true
# reset our 'data' monitor
$hasData = $false
}
'data' {
# we got one!
$hasData = $true
}
}
if($inValues){
# remember to output for the last `values` block
if($hasData){
'data'
} else {
'N/A'
}
}
Ответ №2:
Вы можете использовать Select-String
подход:
# $s contains a single string of your data
($s | Select-String -Pattern '(?s)(?<=values).*?(?=values|$)' -AllMatches).Matches.Value |
Foreach-Object {
('N/A',$matches.0)[$_ -match 'data']
}
Объяснение:
-Pattern
без -SimpleMatch
использования регулярных выражений. (?s)
является однострочным модификатором, который .
соответствует символам новой строки. (?<=values)
является положительным поиском для строки. values
(?=values|$)
является положительным ориентиром для строки values
или ( |
) конца строки ( $
) . Использование lookaheads и lookbehinds values
предотвращает сопоставление, чтобы каждый из них можно было использовать в следующем наборе совпадений. В противном случае, после values
того как он будет сопоставлен, он не сможет быть использован снова в другом условии соответствия. .*?
лениво сопоставляет все символы.
Внутри Foreach-Object
проверяется текущий объект соответствия $_
data
. Если data
найдено, автоматическая переменная $matches
обновляется с ее значением. Поскольку $matches
это хэш-таблица, вам необходимо получить доступ к группе захвата 0
( 0
это имя ключа) для получения значения.
Здесь обязательно должна $s
быть одна строка. Если вы читаете его из текстового файла, используйте $s = Get-Content file.txt -Raw
.
Вы могли бы сделать это немного более динамичным, используя переменные:
$Start = 'values'
$End = 'values'
$data = 'data'
($s | Select-String -Pattern "(?s)(?<=$Start).*?(?=$End|$)" -AllMatches).Matches.Value |
Foreach-Object {
('N/A',$matches.0)[$_ -match 'data']
}
Комментарии:
1. Спасибо, что вы мне очень помогли, но у меня все еще есть две проблемы. Первый заключается в том, что я выполняю другое совпадение раньше и, очевидно, последнее совпадение возобновляется, и я нахожу его в своем списке, поэтому я не знаю, есть ли способ его сбросить. Второй заключается в том, что когда я пытаюсь выполнить поиск нескольких «данных» таким образом: Foreach-Object { (‘N / A’,$matches.0)[$_ -match ‘Data1’] (‘N / A’,$matches.0)[$_ -match ‘Data2’] (‘N / A’,$matches.0)[$_ -сопоставление ‘Data3’] } «N / A» всегда ставят себя на первое место, и поэтому данные выводятся не в правильном порядке.
2. Для второй проблемы просто используйте
('N/A',$matches.0)[$_ -match 'Data1|Data2|Data3']