Переименование строки через матрицу ключ/значение

Я пытаюсь переименовать строки, извлеченные из пользовательского поля. Итак, я настроил матрицу, которая создает связь между тем, что поступает из UDF, и тем, как я хочу переименовать эту строку.

Вот псевдопример моей матрицы (CSV):

Key,Value
FooBar1234,Test 1
ASDF[1234]=qwerty,Test 2
Yellow,Test 3
YellowString,Test 3
1234567890,Test 1
Foo,Test 1
Jane Smith,Test 4
Jane,Test 4
Jane(ABC),Test 4

Вот пример данных, которые получает мой скрипт (CSV):

FooBar1234
ASDF[1234]=qwerty
Yellow
YellowString
1234567890
Foo
Jane Smith
Jane
Jane(ABC)
Jane(abc)

Вот мой сценарий PowerShell:

$path = 'Path\To\CSV\file.csv'

$data = Import-Csv $path -Header UDFName

$matrix = @{}
#import matrix
$re = Import-Csv 'Path\To\Matrix\file.csv' | ForEach-Object{
    #key equals value
    $matrix[$_.Key] = $_.Value
    [regex]::Escape($_.Key)
}
$re = $re -join '|' -as [regex]


$data | ForEach-Object {

    $udf_rename = $re.Replace($_.UDFName,  { $matrix[$args[0].Value] })

    $_.UDFName = $udf_rename

    $_

}| ConvertTo-Csv | Select-Object -Skip 2 | Set-Content $path

И это полный вывод:

"Test 1"
"Test 2"
"Test 3"
"Test 3String"
"Test 1"
"Test 1"
"Test 4"
"Test 4"
"Test 4(ABC)"
"Test 4(abc)"

Проблема, с которой я сталкиваюсь (помимо того факта, что это пользовательское поле 😓), заключается в том, что когда я пытаюсь заменить ключ значением, мой код заменяет только часть входной строки для некоторых входных данных. Например, если YellowString передается через цикл, я ожидаю увидеть Test 3 в качестве результата. Однако, поскольку Yellow,Test 3 является частью матрицы, в результате я получаю Test 3String. Мой цикл заменяет только часть Yellow в YellowString из-за связи, установленной между Yellow и Test 3 в матрице. Нечто подобное происходит с Jane и Jane(ABC).

К сожалению, я не могу удалить Yellow,Test 3 и другие варианты из матрицы, поэтому мне нужно выяснить, как точно сопоставить входную строку. Я попытался удалить все пробелы из ключей, но результат все равно тот же. Я также подумал, что, возможно, я мог бы прикрепить уникальные коды к каждому ключу и затем таким образом перевести, но тогда я столкнулся с той же проблемой, когда дело дошло до замены. Есть идеи? Пожалуйста, дайте мне знать, если я могу предоставить дополнительную информацию.

Ваше совпадение должно происходить слева направо, поэтому YellowString при сопоставлении с Yellow|YellowString будет соответствовать Yellow, а при сопоставлении с YellowString|Yellow будет соответствовать YellowString. Отсортируйте шаблоны регулярных выражений от самого длинного до самого короткого, прежде чем объединять их с помощью каналов. $re = ($re | sort length -descending) -join '|' -as [regex]

TheMadTechnician 25.06.2024 21:36

Есть ли способ сделать это нечувствительным к регистру? Я надеюсь, что Jane(ABC), Test 4 сможет заменить Джейн(abc) и Джейн(ABC).

Crimp 25.06.2024 22:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
82
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Функциональность регулярных выражений PowerShell и API регулярных выражений .NET по умолчанию работают с подстроками.
(Например, 'food' -replace 'oo', '@@' дает 'f@@d', как и ([regex] 'oo').Replace('food', '@@'))

Чтобы гарантировать полное совпадение каждой входной строки, привяжите каждое регулярное выражение к ^...$:

'^{0}$' -f [regex]::Escape($_.Key)

Примечание. В приведенном выше примере используется -f, оператор формата для синтеза строки; альтернативно используйте
'^' + [regex]::Escape($_.Key) + '$' или
"^$([regex]::Escape($_.Key))`$"

Я обдумывал это, но не был уверен, что фраза на замену будет единственной, что будет стоять на кону. Если да, то это лучший ответ

Doug Maurer 25.06.2024 21:56

Для простоты я не упомянул, что данные, которые я передаю скрипту, выглядят примерно так (например, одна строка): A123,FooBar1234,0000,123456789 ... и так далее. Я предполагаю, что опубликованное вами регулярное выражение нацелено на начало строки, поэтому, когда я его вставляю, оно не работает должным образом. Приносим извинения за то, что изначально не были более ясными в отношении данных.

Crimp 25.06.2024 21:57

@Crimp: вы выполняете замену одного свойства ваших CSV-данных, разобранных на объекты ($_.UDFName), поэтому нет необходимости беспокоиться о совпадении во всей строке.

mklement0 25.06.2024 22:08

Спасибо, @DougMaurer; пожалуйста, посмотрите комментарий, который я только что адресовал Кримпу.

mklement0 25.06.2024 22:08

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

Crimp 25.06.2024 22:48

Есть ли способ сделать это нечувствительным к регистру? Например, если YellowString передается через скрипт и yellowstring находится в матрице, цикл не подхватит его и не переименует.

Crimp 25.06.2024 22:51

Рад это слышать, @Crimp. Самый простой способ сделать регулярное выражение нечувствительным к регистру — добавить к строке регулярного выражения встроенный параметр: '(?i)', т. е. $re = '(?i)' + ($re -join '|') -as [regex]. Обратите внимание, что операторы PowerShell по умолчанию обычно нечувствительны к регистру (и имеют варианты с учетом регистра, например -creplace), а в PowerShell (Core) 7 вместо этого можно использовать операцию -replace: $udf_rename = $_.UDFName -replace $re, { $matrix[$_.Value] } (затем можно оставить $re в качестве нить).

mklement0 25.06.2024 23:15

Установите границу слова в регулярном выражении с помощью \b...\b

$path = 'Path\To\CSV\file.csv'

$data = Import-Csv $path -Header UDFName

$matrix = @{}
#import matrix
$re = Import-Csv 'Path\To\Matrix\file.csv' | ForEach-Object{
    #key equals value
    $matrix[$_.Key] = $_.Value
    '\b{0}\b' -f [regex]::Escape($_.Key)
}
$re = $re -join '|' -as [regex]


$data | ForEach-Object {

    $udf_rename = $re.Replace($_.UDFName,  { $matrix[$args[0].Value] })

    $_.UDFName = $udf_rename

    $_

}| ConvertTo-Csv | Select-Object -Skip 2 | Set-Content $path

Выход

udfname
-------
Test 1
Test 2
Test 3
Test 3
Test 1
Test 1
Test 4
Test 4
Test 4(ABC)
Test 4(abc)

Это касается желтой струны.

РЕДАКТИРОВАТЬ

Если вы добавите строчную букву (abc) в свою матрицу, воспользуйтесь предложением @TheMadTechnician и используйте начальную букву \b - тогда это сработает.

$re = $csv | ForEach-Object{
    #key equals value
    $matrix[$_.Key] = $_.Value
    '\b{0}' -f [regex]::Escape($_.Key)
}

$re = ($re | sort length -descending) -join '|'

$data | ForEach-Object {
    if ($_.udfname -match $re){
        $_.UDFName -replace  [regex]::escape($matches[0]),$matrix[$matches[0]]
    }
}

Выход

Test 1
Test 2
Test 3
Test 3
Test 1
Test 1
Test 4
Test 4
Test 4
Test 4

Чтобы обновить свойство, просто присвойте его обратно $_.udfname.

$data | ForEach-Object {
    if ($_.udfname -match $re){
        $_.UDFName = $_.UDFName -replace  [regex]::escape($matches[0]),$matrix[$matches[0]]
    }
}

Есть ли способ справиться с Джейн(ABC) и Джейн(abc)? В моей матрице есть Jane(ABC),Test 4, но с этим решением, похоже, с этим не справиться. Кроме того, я не упомянул, что хотел бы оставить дело без внимания. Я надеюсь, что отношение Jane(ABC),Test 4 сможет заменить Джейн(ABC) и Джейн(abc).

Crimp 25.06.2024 22:00

Простой подход без регулярных выражений:

$data | foreach-object {
    $matrix.ContainsKey($_) ? $matrix[$_] : $_
}

который выводит

Test 1
Test 2
Test 3
Test 3
Test 1
Test 1
Test 4
Test 4
Test 4
Test 4

При этом используется тернарный оператор PowerShell Тернарный (<condition> ? <if-true> : <if-false>) (который недоступен в Windows PowerShell 5.1), чтобы по сути сказать, соответствует ли строка данных ключу в матрице поиска, а затем вернуть значение для этого ключа, в противном случае просто вернуть строку данных. дословно.

Если вам нужно, чтобы он работал в Windows PowerShell 5.1, вы можете использовать немного более длинную форму:

$data | foreach-object {
    if ( $matrix.ContainsKey($_) ) { $matrix[$_] } else { $_ }
}

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

Похожие вопросы