Выбор первых x символов в PowerShell с подвохом - PullRequest
0 голосов
/ 27 октября 2018

$a будет что-то вроде «Углы» или «специальные углы», но может быть таким же, как и «Стандартные оконные проемы до 37», что означает, что простое Substring() не будет работать (чтоЯ в любом случае знаю), если я хочу найти до первых 20 символов в $a (вот и все).

Я обнаружил, что этот бит предназначен для того, что я хочу, но он просто даетme

"char [] ToCharArray (), char [] ToCharArray (int startIndex, int length)"

, и я не знаю, как заставить его работатьправильно.

($a.ToCharArray | select -First 20) -join ""

Ответы [ 3 ]

0 голосов
/ 27 октября 2018

Полезный ответ Lee_Daily хорошо объясняет проблему с вашей попыткой и предлагает рабочее решение, в том числе с использованием унарной формы -join.

Просто дляобъясните будущим читателям , почему с использованием только .Substring() означает , а не , а параметр для реализации extract- не более -N-символов.логика: попытка извлечь подстроку, превышающую длину входной строки, вызывает исключение :

PS> 'abc'.Substring(0, 2) # OK
ab

PS> 'abc'.Substring(0, 4) # !! Exception, because at most 3 chars. can be extracted
Exception [...]: Index and length must refer to a location within the string. [...]

Ваш подход к решению этой проблемы с использованием трубопровода with Select-Object немного сложновато , хотя.

Ниже приведены более эффективные альтернативы, использующие выражения .


Полезный ответ Эсперенто предлагает самое эффективное решение, использующее только функции .NET , хотя это немного "шумно", поскольку требует вызова вложенного метода ипеременная (а не литерал) в качестве входных данных, потому что на эту переменную нужно ссылаться при вызове вложенного метода.
Подходы ниже более PowerShell-идиоматические.

LotPings , вcomment, предлагает краткое решение, основанное на том факте, что строки могут неявно рассматриваться как символьные массивы , поэтому можно применять разбиение массива ;обратите внимание, что индексы основаны на 0 :

PS> -join 'abc'[0..1] 
ab

PS> -join 'abc'[0..3]  # equivalent of: 'abc'.Substring(0, 4), but by default without error
abc

Выражение диапазона 0..3 соответствует массиву 0, 1, 2, 3, в результате чего символы с указанными индексами возвращаются как символмассив, который -join затем собирается в строку.

По умолчанию PowerShell игнорирует индексы за пределами массивов, но предостережение это , еслиSet-StrictMode -Version 3 или выше, выше также вызовет ошибку .


A более эффективная альтернатива, которая не чувствительна к Set-StrictMode, используйте оператор -replace с регулярным выражением (регулярное выражение).
Тем не менее, это решение несколько неясное .

PS> 'abc' -replace '(?<=.{2}).+' # equivalent of 'abc'.Substring(0, 2)
ab

PS> 'abc' -replace '(?<=.{4}).+' # always-safe equivalent of 'abc'.Substring(0, 4)
abc
  • .{4} точно соответствует 4 символам (.) (неявно) в начале строки, без включения этих символов в совпадение ((?<=...), утверждение с предварительным просмотром));.+ затем сопоставляет все оставшиеся символы (один или несколько).

  • Чистый эффект состоит в том, что все входные строки с более 4 символов имеют все из 5-го символа заменяется пустой строкой (из-за отсутствия замещающего операнда), оставляя фактически только первые 4 символа.

  • Входные строки с 4 или менее символов пропускаются как есть (извлечение не требуется).

Для мультистрока входные строки , требуется немного больше работы (встроенный параметр (?s), чтобы . соответствовал символам новой строки (`n) тоже):

PS> "a`nbc" -replace '(?s)(?<=.{3}).+' # extract first 3 chars as string: "a`n"
a
b

Такжерассмотрите возможность использования простой вспомогательной функции :

# Safe equivalent of:
#    $String.Substring($Start)
#    $String.Substring($Start, $Length)
function substr ([string] $String, [int] $Start = 0, [int] $Length = -1) {
  if ($Length -eq -1 -or $Start + $Length -ge $String.Length) {
    $String.Substring($Start)
  }
  else {
    $String.Substring($Start, $Length)
  }
}

Обратите внимание, что вам нужно вызывать ее с синтаксисом аргументов (подобными оболочке, аргументы, разделенные пробелами), как с любой функцией в PowerShell:

PS> substr 'abc' -Length 2 # same as: substr abc 0 2 / substr -String abc -Start 0 -Length 2
ab

PS> substr 'abc' -Length 4
abc

Наконец, обратите внимание, что есть RFC для введения строковых манипуляцийв командлетах (еще не реализовано в PowerShell Core 6.2.0-preview.1), в котором, среди прочего, предлагается командлет Get-Substring для эффективной манипуляции с подстрокой в конвейере.

0 голосов
/ 27 октября 2018

Просто сделай это:

$a.Substring(0, [Math]::Min($a.Length, 20))
0 голосов
/ 27 октября 2018

нет .ToCharArray свойства для строк. то, что вы использовали, даст вам перегрузки для этого метода. [ ухмылка ] попробуйте набрать строку в кавычках, добавить точку и посмотреть, что все показывает.

То, что вы хотите, это .ToCharAray() метод .

Итак, добавьте пропущенные скобки к вызову, и это сработает. [ ухмылка ]

Кроме того, в этой ситуации вам действительно следует использовать "переднюю" версию строкового оператора -join. версия «сзади» предназначена для добавления разделителя. посмотрите на различия [оба дают одинаковый результат] ...

  • -join ('Standard Window Openings up to 37'.ToCharArray() | Select-Object -First 20)
  • ('Standard Window Openings up to 37'.ToCharArray() | Select-Object -First 20) -join ''

1-й пример лучше подходит для вашей настоящей цели.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...