2010-10-22 10 views
27

Mam fajny ciąg CamelCase, taki jak ImageWideNice lub ImageNarrowUgly. Teraz chcę podzielić ten ciąg na jego podłańcuchy, takie jak Image, Wide lub Narrow ilub.Jak podzielić łańcuch CamelCase na jego podciąg w Ruby?

myślałem, że to może być rozwiązany jedynie poprzez

camelCaseString =~ /(Image)((Wide)|(Narrow))((Nice)|(Ugly))/ 

Ale co dziwne, to będzie tylko wypełnić $1 i $2, ale nie $3.

Czy masz lepszy pomysł na podział tego ciągu?

+1

Co byś zrobił z "ThisIsANarrowImageOfHIV?" Czy łączysz się z n, czyli rozdzielasz wirusa HIV? –

Odpowiedz

50
s = 'nowIsTheTime' 

s.split /(?=[A-Z])/ 

=> ["now", "Is", "The", "Time"] 

?=pattern jest przykładem pozytywnej uprzedzona. Zasadniczo pasuje do punktu w ciągu znaków tuż przed wzorcem . Nie zużywa znaków, tzn. Nie zawiera wzorca w ramach meczu. Inny przykład:

irb> 'streets'.sub /t(?=s)/, '-' 
=> "stree-s" 

W tym przypadku s jest dopasowany (tylko drugi t mecze), ale nie zastąpić. Dzięki @Bryce i jego regexp doc link. Bryce Anderson dodaje wyjaśnienie:

?= na początku grupy () meczu nazywa pozytywny uprzedzona, która jest po prostu sposobem na powiedzenie, że podczas gdy regex jest patrząc podczas określania, czy pasuje, nie jest to , co czyni je częścią meczu. split() normalnie zjada między znakami , ale w tym przypadku sam mecz jest pusty, więc nie ma tam nic [tam].

+1

Czy próbowałeś 'NowIsTheTime'? – splash

+1

@splash: nadal działa dobrze – ryeguy

+0

Podczas moich testów to wyrażenie daje "[" "," Teraz "," Jest "," The "," Czas "]' jeśli pierwsza litera jest wielką literą. Co mam nie tak? – splash

2

Czy próbowałeś

camelCaseString =~ /(Image)(Wide|Narrow)(Nice|Ugly)/ 

?

2

Event choć jest to Ruby regex pytanie i answer by DigitalRoss jest poprawna i świeci przez swoją prostotę, chcę dodać odpowiedź Java:

// this regex doesn't work perfect with Java and other regex engines 
"NowIsTheTime".split("(?=[A-Z])"); // ["", "Now", "Is", "The", "Time"] 

// this regex works with first uppercase or lowercase characters 
"NowIsTheTime".split("(?!(^|[a-z]|$))"); // ["Now", "Is", "The", "Time"] 
"nowIsTheTime".split("(?!(^|[a-z]|$))"); // ["now", "Is", "The", "Time"] 
27

wiem, że to jest stary, ale warto wspomnieć o innych, którzy może tego szukać. W szynach można to zrobić: "NowIsTheTime".underscore.humanize

5

odpowiedź DigitalRoss jest prawidłowa, ponieważ obsługuje ogólnym przypadku, gdy nie wiem, czy to ścisła sprawa camel (pierwszy znak małymi literami) lub Pascal przypadek (pisany wielką literą).

Jeśli wiesz, która z tych form znajduje się w łańcuchu lub chcesz wymusić jedno lub drugie, Inflector może to zrobić.

Na razie Pascal:

"NowIsTheTime".titleize 

Na razie wielbłąda:

"nowIsTheTime".titleize.camelize :lower 
+0

Ważne, aby pamiętać, że '# titleize' i' # camelize' to metody ściśle Railsowe, a nie rdzeniowe Ruby. – onebree

0

Odpowiedź od DigitalRoss nie rozpozna akronimów osadzone w CamelCase. Na przykład podzieli "MyHTMLTricks" na "My H T M L Tricks" zamiast "My HTML Tricks".

Oto kolejna opcja na podstawie funkcji AsSpaced() w PmWiki, który ma wielkie zadanie bycia wrażliwe przypadkach tak:

"MyHTMLTricks" \ 
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \ 
.gsub(/([^-\\d])(\\d[-\\d]*(|$))/,'\1 \2') \ 
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2') 

=> "My HTML Tricks" 

Inną rzeczą lubię tego podejścia jest to, że pozostawia ciąg ciąg, zamiast przekształcania go w tablicę. Jeśli naprawdę chcesz tablicę, po prostu dodaj podział na końcu.

"MyHTMLTricks" \ 
.gsub(/([[:lower:]\\d])([[:upper:]])/, '\1 \2') \ 
.gsub(/([^-\\d])(\\d[-\\d]*(|$))/,'\1 \2') \ 
.gsub(/([[:upper:]])([[:upper:]][[:lower:]\\d])/, '\1 \2') \ 
.split 

=> ["My", "HTML", "Tricks"] 

Dla przypomnienia, oto jest oryginalny kod PHP z pmwiki.

function AsSpaced($text) { 
    $text = preg_replace("/([[:lower:]\\d])([[:upper:]])/", '$1 $2', $text); 
    $text = preg_replace('/([^-\\d])(\\d[-\\d]*(|$))/', '$1 $2', $text); 
    return preg_replace("/([[:upper:]])([[:upper:]][[:lower:]\\d])/", '$1 $2', $text); 
} 
Powiązane problemy