Я пытаюсь запустить сценарий PowerShell, который заменит вхождение строки другой строкой. Я хочу удалить угловые скобки из включения и заменить их двойными кавычками только с именем файла заголовка, без пути к папке перед именем файла заголовка. Пример :
#include <a/b/c/def.hpp>
#include <a/b/c/ddd.hpp>
к
#include "def.hpp"
#include "ddd.hpp"
Я пробовал это.
(Get-ChildItem -Recurse | Get-Content | Select-String -Pattern "#include <a/b/c/")-replace '#include <a/b/c/(\w+).*/', '#include "'-replace '>','"'
Благодаря этому я получаю желаемый результат, но не могу использовать результат и заменить существующую строку в исходном файле.
Заранее спасибо.
Мне нужно запросить до 100 файлов в папке. Пожалуйста, предложите лучший способ сделать это.
INPUT
#include <a0/b/c/d/HeaderFile1.hpp>
#include <a1/b/c/d/HeaderFile2.hpp>
#include <a2/b/c/d/HeaderFile3.hpp>
#include <a3/b/c/d/HeaderFile4.hpp>
#include <a4/b/c/d/HeaderFile5.hpp>
#include <a5/b/c/d/HeaderFile6.hpp>
OUTPUT
#include "HeaderFile1.hpp"
#include "HeaderFile2.hpp"
#include "HeaderFile3.hpp"
#include "HeaderFile4.hpp"
#include "HeaderFile5.hpp"
#include "HeaderFile6.hpp"
Возможный дубликат Сценарий PowerShell для поиска и замены всех файлов с определенным расширением





Обновлено: проверено на приведенных вами примерах, если формат может отличаться (более глубокий путь, специальные символы в пути и т. д.), Пожалуйста, проверьте перед. И есть резервная копия
Примерно так должно работать:
$items = Get-ChildItem -Recurse
foreach ($i in $items) {
$newContent = (Get-Content $i) -replace('#include <((\w)+/)*(\w+\.hpp)>','#include "$3"')
$newContent | Set-Content $i
}
После выполнения вышеуказанной команды он запрашивает ввод. командлет Get-Content в позиции 1 конвейера команд. Укажите значения для следующих параметров: Путь [0]:
@LotPings спасибо за ваш комментарий. Я не забуду сделать это в будущем. Просто поправил и протестировал.
@SuryaRao, пожалуйста, проверьте сейчас, я только что исправил и добавил скобки
@robdy: шаблон для файла заголовка, например <a/b/c/def.hpp>, не фиксирован. Это также может быть #include <a/b/c/ddd.hpp>. Поэтому мне нужно написать общий запрос.
Мне придется использовать простое регулярное выражение для захвата всех 4 параметров (если я правильно понимаю, что вы хотите заменить, может быть либо #include <a.hpp>, либо #include <b.hpp>, либо #include <c.hpp>, либо #include <def.hpp>). Я только что отредактировал свой исходный ответ, чтобы добавить это
@rodby: Позвольте мне объяснить это на примере моих ожиданий. Примечание: a0, a1, a2, a3 в начале. Я хочу удалить угловые скобки из включения и заменить их двойными кавычками только с именем файла заголовка, без пути к папке перед именем файла заголовка. INPUT #include <a0 / b / c / d / HeaderFile1.hpp> #include <a1 / b / c / d / HeaderFile2.hpp> #include <a2 / b / c / d / HeaderFile3.hpp> #include <a3 /b/c/d/HeaderFile4.hpp> ВЫХОД #include "HeaderFile1.hpp" #include "HeaderFile2.hpp" #include "HeaderFile3.hpp"
@LotPings: Я только что отредактировал свой вопрос примером. Надеюсь, это объяснит. Спасибо
Я пробовал следующее, с которым я получаю желаемый результат, но остальное содержимое файла стирается, и изменяется только желаемая строка заголовка. $items = Get-ChildItem -Recurse foreach ($i in $items) { $newContent = ((Get-Content $i) | Select-String -Pattern "#include <a0/b/c/")-replace '#include <a0/b/c/(\w+).*/', '#include "'-replace '>','"' $newContent | Set-Content $i }
Я думаю, что мне удалось построить для него регулярное выражение, проверьте редактирование
@robdy: я пробовал регулярное выражение. работает нормально. Благодарю. Можем ли мы также исключить преобразование определенных строк в некоторых случаях здесь, используя регулярное выражение? Пример: Любое включение, которое начинается с «MyFolder», не должно изменять строку заголовка включения. `#include <MyFolder / Myfile.h> 'не следует изменять
Это тоже возможно, но я предлагаю вам приложить некоторые усилия и попробовать это самостоятельно. На ваш первоначальный вопрос уже дан ответ, и, пожалуйста, помните, что мы здесь, чтобы помочь, а не писать за вас весь код. regexr.com - отличное место, чтобы помочь вам (подсказка: может быть полезен отрицательный набор). Удачи!
Вам просто нужно записать новый текст обратно в файл. вот мой способ сделать это:
Get-ChildItem -Recurse -File | ForEach-Object {
(Get-Content $_).replace('#include <a/b/c/def.hpp>','#include "def.hpp"') | Set-Content $_
}
Редактировать:
Теперь, когда вы объяснили свой вопрос, ясно, что вам нужно использовать регулярное выражение. тот, который опубликовал LotPings, будет работать нормально. поэтому, используя его RegEx, правильный ответ:
Get-ChildItem -Recurse -File | ForEach-Object {
(Get-Content $_)-replace('(?<=#include ).*/([^>]+)>','"$1"') | Set-Content $_
}
Шаблон для файла заголовка, например <a/b/c/def.hpp>, не фиксирован. Это также может быть #include <a/b/c/ddd.hpp>. Итак, мне нужно написать общий запрос
@SuryaRao Не могли бы вы объяснить точно, как выглядят заголовки?
Идея состоит в том, чтобы удалить угловые скобки из строки incude и заменить их двойными кавычками. А также укажите иерархию папок в строке включения.
Я создал несколько тестовых файлов, содержащих ваши образцы:
> Select-String file*.cpp -patt 'hpp'
File1.cpp:1:#include <a0/b/c/d/HeaderFile1.hpp>
File2.cpp:1:#include <a1/b/c/d/HeaderFile2.hpp>
File3.cpp:1:#include <a2/b/c/d/HeaderFile3.hpp>
File4.cpp:1:#include <a3/b/c/d/HeaderFile4.hpp>
File5.cpp:1:#include <a4/b/c/d/HeaderFile5.hpp>
File6.cpp:1:#include <a5/b/c/d/HeaderFile6.hpp>
Следующий скрипт использует RegEx, объясненный в прямом эфире на RegEx101 и ниже static.
## Q:\Test\2018\06\09\SO_50777494.ps1
## the following RegEx usees a positive lookbehind and a
## capture group for the filename.
[RegEx]$Search = '(?<=#include ).*/([^>]+)>'
$Replace = '"$1"'
ForEach ($File in (Get-ChildItem -Path '.\File*.cpp' -Recurse -File)) {
(Get-Content $File) -Replace $Search,$Replace |
Set-Content $File
}
Пример вывода Select-String после замены:
> sls file*.cpp -patt 'hpp'
File1.cpp:1:#include "HeaderFile1.hpp"
File2.cpp:1:#include "HeaderFile2.hpp"
File3.cpp:1:#include "HeaderFile3.hpp"
File4.cpp:1:#include "HeaderFile4.hpp"
File5.cpp:1:#include "HeaderFile5.hpp"
File6.cpp:1:#include "HeaderFile6.hpp"
Объяснение RegEx:
(?<=#include ).*/([^>]+)>
Positive Lookbehind (?<=#include )
Assert that the Regex below matches
#include matches the characters #include literally
.*
. matches any character (except for line terminators)
* Quantifier — Matches between zero and unlimited times,
as many times as possible, giving back as needed (greedy)
/ matches the character / literally (case sensitive)
1st Capturing Group ([^>]+)
Match a single character not present in the list below [^>]+
+ Quantifier — Matches between one and unlimited times,
as many times as possible, giving back as needed (greedy)
> matches the character > literally (case sensitive)
Пожалуйста, проверьте сообщение stackoverflow.com/questions/2837785/…, в нем приведен пример того, как найти и заменить строку в нескольких файлах.