2015-01-14 13 views
5

Czy to możliwe, w PowerShell, aby obciąć ciąg, (używając SubString()?), Do danej maksymalnej liczby znaków, nawet jeśli oryginalny ciąg jest już krótszy?podciągu w PowerShell obciąć długość ciągu

Na przykład:

foreach ($str in "hello", "good morning", "hi") { $str.subString(0, 4) } 

obcięcie pracuje dla hello i good morning ale pojawia się błąd za hi.

chciałbym następujący wynik:

hell 
good 
hi 
+0

Chcesz dodać znaki, jeśli są krótsze i usunąć je, jeśli są dłuższe? – arco444

+0

jeśli jest krótszy, zachowaj ciąg w obecnej postaci, bez potrzeby dodawania znaków. –

Odpowiedz

14

Trzeba ocenić aktualną pozycję i uzyskać długość niego. Jeśli długość jest mniejsza niż 4, użyj tego w funkcji podłańcuchowej.

foreach ($str in "hello", "good morning", "hi") { 
    $str.subString(0, [System.Math]::Min(4, $str.Length)) 
} 
1

Można by pułapka wyjątek:

foreach ($str in "hello", "good morning", "hi") { 
    try { 
    $str.subString(0, 4) 
    } 
    catch [ArgumentOutOfRangeException] { 
    $str 
    } 
} 
0

Można również użyć -replace

foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','$1' } 

hell 
good 
hi 
+1

Twoje dane wyjściowe nie są zgodne z oczekiwaniami. – Duncan

+0

@Duncan Twoje prawo. Naprawiony – mjolinor

5

Albo może po prostu keep it simple, wykorzystujących alternatywne PowerShell do operatora potrójnego:

foreach ($str in "hello", "good morning", "hi") { 
    $(if ($str.length -gt 4) { $str.substring(0, 4) } else { $str }) 
} 

Podczas gdy wszystkie pozostałe odpowiedzi są "poprawne", ich efektywność zmienia się z nieoptymalnej na potencjalnie przerażającą. Poniższe nie stanowi krytyki innych odpowiedzi, ale ma na celu pouczające porównanie ich podstawowej działalności. W końcu tworzenie skryptów polega raczej na szybkim uruchomieniu systemu niż na szybkim uruchomieniu.

w celu:

1.

foreach ($str in "hello", "good morning", "hi") { 
    $str.subString(0, [System.Math]::Min(4, $str.Length)) 
} 

To jest w zasadzie taka sama jak moja ofiara tą różnicą, że zamiast po prostu powrocie $ str, gdy jest zbyt krótki, wzywamy podciąg i poinformować go, aby powrócić cały ciąg. Stąd nieoptymalne. Nadal robi się, jeśli ... następnie ... ale tylko wewnątrz Min, vis.

if (4 -lt $str.length) {4} else {$str.length} 

2.

foreach ($str in "hello", "good morning", "hi") { $str -replace '(.{4}).+','$1' } 

Korzystanie wyrażenie regularne pasujące do chwycić pierwsze 4 znaki i wtedy wymienić cały łańcuch z nich oznacza, że ​​cała (prawdopodobnie bardzo długo) łańcuch musi być skanowane przez dopasowanie silnik o nieznanej złożoności/wydajności. Podczas gdy osoba może zobaczyć, że ". +" Jest po prostu dopasowane do całej pozostałej części łańcucha, dopasowany silnik może budować dużą listę alternatyw cofania, ponieważ wzór nie jest zakotwiczony (nie^na początku). Tutaj (nieopisany) sprytny bit jest taki, że jeśli ciąg znaków jest mniejszy niż 5 znaków (4 razy, po którym następuje 1 lub więcej), to cały mecz kończy się niepowodzeniem i zastępuje zwrot $ str niezmieniony.

3.

foreach ($str in "hello", "good morning", "hi") { 
    try { 
    $str.subString(0, 4) 
    } 
    catch [ArgumentOutOfRangeException] { 
    $str 
    } 
} 

Celowo rzucanie wyjątki zamiast programowej kontroli granicznej jest ciekawym rozwiązaniem, ale kto wie, co się dzieje, gdy wyjątek propaguje się z bloku spróbować połowu. Prawdopodobnie niewiele w tym prostym przypadku, ale nie byłoby to zalecaną praktyką powszechną, z wyjątkiem sytuacji, w których istnieje wiele możliwych źródeł błędów (sprawiających kłopoty z sprawdzeniem ich wszystkich), ale tylko kilka odpowiedzi.

Co ciekawe, odpowiedź na podobne pytanie w innym miejscu za pomocą -join i plastry array (które nie powodują błędów na indeks poza zakresem, po prostu zignorować brakujących elementów)

$str[0..3] -join "" # infix 

(lub prościej)

-join $str[0..3]  # prefix 

może być najbardziej efektywny (z odpowiednią optymalizacją), biorąc pod uwagę silne podobieństwo między przechowywaniem ciągów i znakami []. Optymalizacja byłaby wymagana, ponieważ domyślnie $ str [0..3] jest obiektem [], przy czym każdy element jest pojedynczym znakiem, a więc mało przypomina on ciąg (w pamięci). Nadanie PowerShell trochę wskazówka może być przydatna,

-join [char[]]$str[0..3] 

Jednak może po prostu mówi to, co rzeczywiście chcą,

new-object string (,$str[0..3]) # need $str[0..3] to be a member of an array of constructor arguments 

co bezpośrednio powołując

new String(char[]) 

jest najlepszy.

Powiązane problemy