Как разбить строку на подстроки?

#powershell

#powershell

Вопрос:

У меня есть файл с именем collection.xml который содержит список фильмов из моей коллекции пасхальных фильмов, показанный ниже. Как только я получу их, я пытаюсь использовать Split для разделения файлов на строки «Movies /» и . Это приведет к появлению таких названий фильмов, как:

Пасхальный кролик приезжает в город (2006).mp4

Я пробовал различные перестановки Split() и модификатора -split . Как я могу разделить вывод ниже, чтобы получить только названия фильмов, как показано выше?

 Get-Content .collection.xml | Select-String Path

      <Path>/volume1/Media Library/Movies/Here Comes Peter Cottontail (1971).mp4</Path>
      <Path>/volume1/Media Library/Movies/Here Comes Peter Cottontail - The Movie (2005).mp4</Path>
      <Path>/volume1/Media Library/Movies/The Easter Bunny is Coming to Town (2006).mp4</Path>
      <Path>/volume1/Media Library/Movies/Its The Easter Beagle Charlie Brown (2008).mp4</Path>
      <Path>/volume1/Media Library/Movies/Hop (2011).mp4</Path>
      <Path>/volume1/Media Library/Movies/Peter Rabbit (2018).mp4</Path>
  

Ответ №1:

Это просто, если вы рассматриваете это как XML-файл, полный имен файлов, поскольку вы можете сделать это в одной строке; Я разбил на несколько для удобства чтения:

Вариант 1:

 ([xml](get-content temp.txt)).SelectNodes("//Path") | foreach-object {
    [io.path]::GetFileNameWithoutExtension($_.'#text') 
}
  

Это эффективно:

  1. Считывает файл в формате XML
  2. Выбирает все узлы «пути» в файле — возможно, вам потребуется настроить это, чтобы лучше соответствовать вашему фактическому XML-файлу. Это простой XPath.
  3. Для каждого найденного узла вызовите .Собственный метод NET над текстовой частью узла для извлечения имени файла

Вариант 2:

Практически то же самое, но с использованием более собственных командлетов XML, что может упростить чтение:

 (select-xml -xpath '//Path' -path .temp.txt).Node | foreach-object { 
    [io.path]::GetFilenameWithoutExtension($_.'#text') 
}
  

Опять же, настройте XPath в соответствии с вашим XML-файлом.

Существуют различные способы структурирования обоих из них на ваш вкус (и точного формата XML), перемещая селекторы «.Node» и «.’#text'» внутри (или снаружи) foreach; например, мы можем убрать скобки select-xml в строке выше, переместив узел в пределахforeach:

 select-xml -xpath '//Path' -path .temp.txt | foreach-object { 
    [io.path]::GetFilenameWithoutExtension($_.Node.'#text') 
}
  

…и вариации на тему. На это может повлиять ваша структура файла XML; все остальное зависит от личных предпочтений и удобства чтения.

Комментарии:

1. Спасибо, это работает идеально! Для этого я должен был использовать XML-инструменты PowerShell. Скажите мне, что такое параметр ‘#text’?

2. XML-файл — это просто набор узлов. Текст между открывающим и закрывающим тегами в XML — это сам узел, который (в случае Powershell) он присваивает #text псевдо-узлу. Итак, если вы просто сделаете (скажем) (select-xml -xpath '//Path' -path file).Node , вы увидите, что вывод — это содержимое всех ваших узлов пути в столбце с заголовком (т. Е. Свойством) #text . Если вы это сделаете (select-xml -xpath '//Path' -path file).Node | get-member , это покажет, что #text свойство имеет тип XmlElement . Доступ #text как свойство в PS затем просто дает текстовое значение (через неявное ToString() ).

3. Я должен добавить, #text в одинарных кавычках в основном ответе, потому что свойства Powershell не могут (обычно) начинаться со специальных символов. Поэтому для экранирования имени пропети нужны одинарные кавычки (и не выдавать синтаксическую ошибку).

Ответ №2:

Поскольку я не знаю, как выглядит ваш полный XML-файл, я сделал это, используя только предоставленную вами информацию и несколько простых регулярных выражений.

Здесь я делаю пару предположений

  1. Ваш путь к файлу всегда заканчивается на «Фильмы»
  2. Вам не нужен тип файла в конце строки
 $banana = Get-Content C:Tempcollection.xml | Select-String Path

foreach($line in $banana)
{
    #load the line as an xml object, expand the path property, and replace the characters we don't want.
    ([xml]$line).Path -replace "^/. Movies/|.. $"

}
  

Эти иероглифы после -replace означают это

^ : Начало строки

/ : Буквенный / символ

. : Любой символ (кроме символов завершения строки)

: Хотя бы один, но до бесконечности

Movies : Литеральная строка «Фильмы»

/ : Буквенный / символ

| : Или

. : Буквенный . символ (точка)

. : . и комбинированный, что означает любой символ хотя бы один раз, но до бесконечности

$ : Конец строки