2013-11-11 4 views
8

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

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

Теперь я пытаюсь выяснить, как заменить подраздел каждого совпадения регулярного выражения. Можно ли это сделать одним плавным шагом, как описано выше? Или вам нужно извлечь каждое совпадение большего регулярного выражения, выполнить поиск и заменить его, а затем каким-то образом вернуть этот результат в исходный текст?

Чтобы пояснить в примере, предположим, что в следующем тестовом тексте я хочу найти только 14xx-нумерованные экземпляры типа «TEST = * 1404» в следующем тексте и заменить 14xx на 16xx?

A 2180 1830 12 0 3 3 TEST=C1404 
A 900 1830 12 0 3 3 TEST=R1413 
A 400 1830 12 0 3 3 TEST=R1411 
A 1090 1970 12 0 3 3 TEST=U1400 
A 1090 1970 12 0 3 3 TEST=CSA1400 
A 1090 1970 12 0 3 3 TEST=CSA1414 
A 1090 1970 12 0 3 3 TEST=CSA140 
A 1090 1970 12 0 3 3 TEST=CSA14001 
A 1090 1970 12 0 3 3 TEST=CSA17001 

I.e. Я хотел бы в результате текст будет следующим образом, где вы можете заметить, что только первые 6 строк следует изменить:

A 2180 1830 12 0 3 3 TEST=C1604 
A 900 1830 12 0 3 3 TEST=R1613 
A 400 1830 12 0 3 3 TEST=R1611 
A 1090 1970 12 0 3 3 TEST=U1600 
A 1090 1970 12 0 3 3 TEST=CSA1600 
A 1090 1970 12 0 3 3 TEST=CSA1614 <- Second instance of '14' shouldn't change 
A 1090 1970 12 0 3 3 TEST=CSA140 <- Shorter numbers shouldn't change 
A 1090 1970 12 0 3 3 TEST=CSA14001 <- Longer numbers shouldn't change 
A 1090 1970 12 0 3 3 TEST=CSA17001 

следующее регулярное выражение, кажется, делает работу по поиску больших строк, где мне нужно make replace, но я не знаю, какую функциональность в Powershell (replace?) использовать, чтобы просто заменить подстроку результатов. Кроме того, не стесняйтесь предлагать лучшее регулярное выражение, если это поможет.

$regexA = "\bTEST=\b[A-Za-z]+14\d\d\r" 

Я предпочел бы не иметь код с жёстким исчерпывающий перечень вещей, которые могут прийти между «=» и числами, как «R», «C», «CSA» и т.д.

Я работаю над чем-то в течение часа или около того, где я получаю все совпадения для регулярного выражения, поиск в них, чтобы заменить 14 на 16, а затем запустите в исходном тексте старые и новые значения, например replace($myText,"TEST=CSA1400","TEST=CSA1600"), но это не очень хорошо закрывает особые случаи, и мне кажется, что я направляюсь вниз по кроличьей дыре.

ответ

16

Вам нужно сгруппировать суб-выражения, которые вы хотите сохранить (например, поместите их между круглыми скобками), а затем ссылку на группы с помощью переменных $1 и $2 в заменяющей строке. Попробуйте что-то вроде этого:

$regexA = '(TEST=[A-Za-z]+)14(\d\d)$' 

Get-ChildItem "*.txt" | % { 
    $c = (Get-Content $_.FullName) -replace $regexA,'${1}16$2' -join "`r`n" 
    [IO.File]::WriteAllText($_.FullName, $c) 
} 
+0

+1 Я почесал голову над тем, чтобы ускользнуть от этой замены. – mjolinor

+0

В вашем методе существует ли опасность добавления '-raw' в' Get-Content' и удаления 'join' из замещающей части? – SSilk

+0

@SSilk Это тоже должно работать, но вам нужно заменить '' 'в регулярном выражении чем-то вроде' (\ r | $) '. –

1

Попробуйте это:

Get-ChildItem "*.txt" | 
Foreach-Object { 
    $c = $_ | Get-Content | Foreach {$_ -replace '(?<=TEST=\D+)14(?=\d{2}(\D+|$))','16'} 
    $c | Out-File $_.FullName -Enc Ascii 
} 
+1

'$ f = $ _. FullName; (Get-Content $ f) -replace ... | Out-File $ f ... ', вероятно, более элегантный подход. –

0

Вот пример использования ScriptBlock делегата (иногда называемый оценщик):

$regex = [regex]'(TEST=\D+)14(\d{2})\s*$' 
$evaluator = { '{0}16{1}' -f $args[0].Groups[1..2] } 
filter set-number { $regex.Replace($_, $evaluator) } 

foreach ($file in Get-ChildItem "*.txt") 
{ 
    ($file | get-content) | set-number | Set-Content $file.FullName 
} 

Это, пожалуй, более сложным, чем - замените оператор, но вы можете использовать операторы powershell для создания заменяющего текста, чтобы вы могли делать все, что можно добавить в блок сценариев.

Смежные вопросы