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

Я ищу способ рандомизировать определенную строку в огромном файле, используя предопределенные строки из массива, без необходимости записи временного файла на диск.

Существует файл, который содержит ту же строку, например. «ABC123456789» во многих местах:

<Id>ABC123456789</Id><tag1>some data</tag1><Id>ABC123456789</Id><Id>ABC123456789</Id><tag2>some data</tag2><Id>ABC123456789</Id><tag1>some data</tag1><tag3>some data</tag3><Id>ABC123456789</Id><Id>ABC123456789</Id>

Я пытаюсь рандомизировать эту строку «ABC123456789», используя массив или список определенных строк, например. "@('foo','bar','baz','foo-1','bar-1')". Каждая ABC123456789 должна быть заменена случайно выбранной строкой из массива/списка.

В итоге я получил следующее решение, которое работает «отлично». Но это определенно не правильный подход, так как он сильно экономит на диске - по одному на каждую заменяемую строку и поэтому очень медленный:

$inputFile = Get-Content 'c:\temp\randomize.xml' -raw
$checkString = Get-Content -Path 'c:\temp\randomize.xml' -Raw | Select-String -Pattern '<Id>ABC123456789'
[regex]$pattern = "<Id>ABC123456789"

while($checkString -ne $null) {
    $pattern.replace($inputFile, "<Id>$(Get-Random -InputObject @('foo','bar','baz','foo-1','bar-1'))", 1) | Set-Content 'c:\temp\randomize.xml' -NoNewline
    $inputFile = Get-Content 'c:\temp\randomize.xml' -raw
    $checkString = Get-Content -Path 'c:\temp\randomize.xml' -Raw | Select-String -Pattern '<Id>ABC123456789'
}
Write-Host All finished

Вывод рандомизирован, например:

<Id>foo
<Id>bar
<Id>foo
<Id>foo-1

Однако я хотел бы добиться такого вывода без необходимости записи файла на диск на каждом этапе. Для тысяч вхождений строк требуется много времени. Любая идея, как это сделать?

========================== Редактировать 2023-02-16

Я попробовал решение от zett42, и оно отлично работает с простой структурой XML. В моем случае есть некоторые сложности, которые не были важны в моем подходе к обработке текста. Имена корневого и некоторых других элементов в структуре обрабатываемого XML-файла содержат двоеточие, и для этой ситуации должна быть какая-то специальная настройка для "-XPath". Или, может быть, решение выходит за рамки Powershell.

<?xml version='1.0' encoding='UTF-8'?>
<C23A:SC777a xmlns = "urn:C23A:xsd:$SC777a" xmlns:C23A = "urn:C23A:xsd:$SC777a" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "urn:C23A:xsd:$SC777a SC777a.xsd">
    <C23A:FIToDDD xmlns = "urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02">
        <CxAAA>
            <DxBBB>
                <ABC>
                    <Id>ZZZZZZ999999</Id>
                </ABC>
            </DxBBB>
            <CxxCCC>
                <ABC>
                    <Id>ABC123456789</Id>
                </ABC>
            </CxxCCC>
        </CxAAA>
        <CxAAA>
            <DxBBB>
                <ABC>
                    <Id>ZZZZZZ999999</Id>
                </ABC>
            </DxBBB>
            <CxxCCC>
                <ABC>
                    <Id>ABC123456789</Id>
                </ABC>
            </CxxCCC>
        </CxAAA>
    </C23A:FIToDDD>
    <C23A:PmtRtr xmlns = "urn:iso:std:iso:20022:tech:xsd:pacs.004.001.02">
        <GrpHdr>
            <TtREEE Abc = "XV">123.45</TtREEE>
            <SttlmInf>
                <STTm>ABCA</STTm>
                <CLss>
                    <PRta>SIII</PRta>
                </CLss>
            </SttlmInf>
        </GrpHdr>
        <TxInf>
            <OrgnlTxRef>
                <DxBBB>
                    <ABC>
                        <Id>YYYYYY888888</Id>
                    </ABC>
                </DxBBB>
                <CxxCCC>
                    <ABC>
                        <Id>ABC123456789</Id>
                    </ABC>
                </CxxCCC>
            </OrgnlTxRef>
        </TxInf>
    </C23A:PmtRtr>
</C23A:SC777a>

Вы пытаетесь выполнить маскирование данных для файла XML?

vonPryz 15.02.2023 10:11

Речь не идет о маскировке данных. У меня есть набор данных в файле xml, который имеет повторяющуюся часть, и мне нужно сделать его менее «однородным» для целей тестирования, в то время как мне нужно использовать предоставленный набор строк для его достижения.

maro 15.02.2023 10:26

Просмотр и просмотр непосредственно сериализованной строки (например, XML ) с использованием строковых методов (таких как -Replace) — плохая идея. Вместо этого вы должны использовать соответствующий парсер для поиска и замены. См., например: Регулярное выражение Powershell для замены текста между двумя строками

iRon 15.02.2023 10:59

Что касается вашего редактирования, используйте Select-Xml с параметром -Namespace следующим образом: Select-Xml -XPath '//a:Id/text()' -Namespace @{a = 'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02'}

zett42 17.02.2023 12:08

@ zett42 Я уже сделал это, когда ты упомянул об этом в своем ответе. Я также тестировал код на разных наборах XML, и после изменения «Пространства имен» он работал очень хорошо. Еще раз спасибо.

maro 20.02.2023 09:01
Руководство для начинающих по веб-разработке на React.js
Руководство для начинающих по веб-разработке на React.js
Веб-разработка - это захватывающая и постоянно меняющаяся область, которая постоянно развивается благодаря новым технологиям и тенденциям. Одним из...
Разница между Angular и React
Разница между Angular и React
React и AngularJS - это два самых популярных фреймворка для веб-разработки. Оба фреймворка имеют свои уникальные особенности и преимущества, которые...
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Инструменты для веб-скрапинга с открытым исходным кодом: Python Developer Toolkit
Веб-скрейпинг, как мы все знаем, это дисциплина, которая развивается с течением времени. Появляются все более сложные средства борьбы с ботами, а...
Калькулятор CGPA 12 для семестра
Калькулятор CGPA 12 для семестра
Чтобы запустить этот код и рассчитать CGPA, необходимо сохранить код как HTML-файл, а затем открыть его в веб-браузере. Для этого выполните следующие...
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
ONLBest Online HTML CSS JAVASCRIPT Training In INDIA 2023
О тренинге HTML JavaScript :HTML (язык гипертекстовой разметки) и CSS (каскадные таблицы стилей) - две основные технологии для создания веб-страниц....
Как собрать/развернуть часть вашего приложения Angular
Как собрать/развернуть часть вашего приложения Angular
Вам когда-нибудь требовалось собрать/развернуть только часть вашего приложения Angular или, возможно, скрыть некоторые маршруты в определенных средах?
1
5
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как уже отмечалось, не рекомендуется обрабатывать XML как текстовый файл. Это хрупкий подход, который слишком сильно зависит от форматирования XML. Вместо этого используйте правильный анализатор XML для загрузки XML и последующей обработки его элементов объектно-ориентированным способом.

# Use XmlDocument (alias [xml]) to load the XML
$xml = [xml]::new(); $xml.Load(( Convert-Path -LiteralPath input.xml ))

# Define the ID replacements
$searchString = 'ABC123456789'
$replacements = 'foo','bar','baz','foo-1','bar-1'

# Process the text of all ID elements that match the search string, regardless how deeply nested they are.
$xml | Select-Xml -XPath '//Id/text()' | ForEach-Object Node |
       Where-Object Value -eq $searchString | ForEach-Object {

    # Replace the text of the current element by a randomly choosen string
    $_.Value = Get-Random $replacements 
}

# Save the modified document to a file
$xml.Save( (New-Item output.xml -Force).Fullname )
  • $xml | Select-Xml -XPath '//Id/text()' выбирает текстовые узлы всех Id элементов, независимо от того, насколько глубоко они вложены в XML DOM, с помощью универсальной команды Select-Xml . Узлы XML выбираются путем указания выражения XPath.
    • Что касается вашего редактирования, когда вам приходится иметь дело с пространствами имен XML, используйте параметр -Namespace, чтобы указать префикс пространства имен, который будет использоваться в выражении XPath для данного URI пространства имен. В этом примере я просто выбрал a в качестве префикса пространства имен:
      $xml | Select-Xml -XPath '//a:Id/text()' -Namespace @{a = 'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.02'}
      
  • ForEach-Object Node выбирает свойство Node из каждого результата Select-Xml. Это упрощает следующий код.
  • Where-Object Value -eq $searchString выбирает текстовые узлы, соответствующие строке поиска.
  • Внутри ForEach-Object переменная $_ обозначает текущий текстовый узел. Назначьте его свойству Value изменение текста.
  • Вызовы Convert-Path и New-Item позволяют использовать относительный путь PowerShell (PSPath) с классом .NET XmlDocument. Как правило, .NET API ничего не знают о текущем каталоге PowerShell, поэтому нам нужно преобразовать пути перед переходом к .NET API.

Наконец, я обнаружил, что ваше решение подходит для моей цели, поскольку я могу отделить соответствующую часть кода XML, использовать эту замену, а затем вставить эту часть обратно в окончательный файл XML между открывающей и закрывающей частями. И этот способ синтаксического анализа XML действительно намного быстрее! Спасибо.

maro 16.02.2023 22:35

Другие вопросы по теме