Regex, aby usunąć wiodące zera w R, chyba że ostatni (lub tylko) znak ma wartość zero

9
gsub("(?<![0-9])0+", "", c("005", "0AB", "000", "0"), perl = TRUE)
#> [1] "5"  "AB" ""   ""
gsub("(^|[^0-9])0+", "\\1", c("005", "0AB", "000", "0"), perl = TRUE)
#> [1] "5"  "AB" ""   ""

Powyższe wyrażenie regularne pochodzi z tego wątku SO wyjaśniającego, jak usunąć wszystkie zera wiodące z ciągu w R. W wyniku tego wyrażenia regularnego zarówno „000”, jak i „0” są przekształcane w „”. Zamiast tego chcę usunąć wszystkie wiodące zera z ciągu znaków, z wyjątkiem przypadków, gdy końcowy znak ma wartość zero lub jedynym znakiem jest zero.

"005" would become "5"
"0AB" would become "AB"
"000" would become "0"
"0"   would become "0"

Ten drugi wątek SO wyjaśnia, jak zrobić to, co chcę, ale nie wydaje mi się, że otrzymuję poprawną składnię, stosując rozwiązanie w R. I tak naprawdę nie rozumiem różnicy między pierwszym i drugim rozwiązaniem poniżej ( jeśli rzeczywiście działały).

gsub("s/^0*(\d+)$/$1/;", "", c("005", "0AB", "000", "0"), perl = TRUE)  # 1st solution
# Error: '\d' is an unrecognized escape in character string starting ""s/^0*(\d"
gsub("s/0*(\d+)/$1/;", "", c("005", "0AB", "000", "0"), perl = TRUE)    # 2nd solution
# Error: '\d' is an unrecognized escape in character string starting ""s/0*(\d"

Jaki jest poprawny wyraz regularny w R, aby uzyskać to, czego chcę?

Jason Hunter
źródło

Odpowiedzi:

6

Możesz usunąć wszystkie zera z początku łańcucha, ale nie z ostatniego:

sub("^0+(?!$)", "", x, perl=TRUE)

Zobacz demo wyrażenia regularnego .

Detale

  • ^ - początek łańcucha
  • 0+ - jedno lub więcej zer
  • (?!$) - negatywne spojrzenie w przód, które nie powiedzie się, jeśli koniec łańcucha znajduje się bezpośrednio po prawej stronie bieżącej lokalizacji

Zobacz wersję demo R :

x <- c("005", "0AB", "000", "0")
sub("^0+(?!$)", "", x, perl=TRUE)
## => [1] "5"  "AB" "0"  "0"
Wiktor Stribiżew
źródło
1
regexNowicjusz. Jaka jest różnica w wydajności (lub innych preferencjach) między twoim wzorcem a tym ^0*(.+)$lub ^0+(.+)$?
M--
2
@ M-- Są to różne wzorce, zaleca się porównywanie tylko wydajności równoważnych wyrażeń regularnych. Twoje są trochę nieefektywne, jak .można dopasować, 0a oba sąsiednie wzorce są nieokreślone ilościowo, ale tylko trochę.
Wiktor Stribiżew,
4

Możemy dodać jeszcze jeden warunek z wyrażeniem regularnym, aby sprawdzić wartości niezerowe po jednym lub więcej zerach ( 0+)

sub("(?<![0-9])0+(?=[^0])", "", sub("^0+$", "0", v1), perl = TRUE)
#[1] "5"  "AB" "0"  "0" 

dane

v1 <- c("005", "0AB", "000", "0")
akrun
źródło
1
Nie jestem regexw żaden sposób guru, ale spojrzenia nie są skuteczne, prawda? Ponieważ masz dwa, submożesz usunąć wszystkie wiodące zera i zastąpić ""je 0? sub("^$", "0", sub("^0+", "", v1), perl = TRUE)
M--
2
@ M-- To nie byłoby tak wydajne, ale użyłem go do przestrzegania tego samego kodu, co OP
akrun
3

Możesz użyć alternacji, aby dopasować wszystkie zera w ciągu w grupie przechwytywania lub dopasować wszystkie zera od początku ciągu.

W zastępczej grupie zastosowań 1.

^0*(0)$|^0+

Wersja demo | Demo R.

Na przykład

sub("^0*(0)$|^0+", "\\1", c("005", "0AB", "000", "0"))

Wynik

[1] "5"  "AB" "0"  "0"

Lub nawet lepiej, jak komentuje Wiktor Stribiżew , możesz użyć przechwytywania pojedynczego 0 w grupie i powtarzania samej grupy, aby uchwycić ostatnie wystąpienie zera.

^(0)+$|^0+

Demo Regex

Czwarty ptak
źródło
3
Użyłbym^(0)+$|^0+
Wiktor Stribiżew
3
Wygląda na to, sub("^0+(?!$)", "", x, perl=TRUE)że również zadziała
Wiktor Stribiżew,
2

Inna regexopcja:

^0*(.+)$

Oto demo wyrażenia regularnego .

Używanie base::subw R:

sub("^0*(.+)$", "\\1", c("005", "0AB", "000", "0"))  

 ## [1] "5"  "AB" "0"  "0" 

Oto demo R .

Lub rozwinięcie odpowiedzi @ akrun :

sub("^$", "0", sub("^0+", "", c("005", "0AB", "000", "0")), perl = TRUE)
M--
źródło