Jak zacząć wielką literę w ciągu znaków w języku Ruby

139

upcaseSposób aktywuje cały ciąg, ale muszę wykorzystać tylko pierwszą literę.

Muszę też obsługiwać kilka popularnych języków, takich jak niemiecki i rosyjski.

Jak mam to zrobić?

AntonAL
źródło
4
Należy pamiętać, że niektóre języki mają różne wyobrażenia o tym, jaka jest pierwsza litera, która ma być wielka. W języku irlandzkim robisz takie rzeczy, jak „i mBaile Átha Cliath” („w Dublinie”) - małe litery „m”, duże litery „B”. (Zobacz en.wikipedia.org/wiki/Consonant_mutation#Celtic_languages, jeśli jesteś ciekawy, dlaczego Irish to zrobił i dlaczego ma to sens.)
James Moore,
4
Pamiętaj też, że #capitalize spowoduje zmniejszenie wszystkich liter, które nie są pierwszą literą ... co nie zawsze jest tym, czego chcesz. ['space', 'UFO', 'NASA'].collect{|w| w.capitalize} #=> ['Space', 'Ufo', 'Nasa']
Huliax

Odpowiedzi:

264

To zależy od używanej wersji Ruby:

Ruby 2.4 i nowsze:

Po prostu działa, ponieważ Ruby v2.4.0 obsługuje mapowanie wielkości liter w formacie Unicode:

"мария".capitalize #=> Мария

Ruby 2.3 i starsze:

"maria".capitalize #=> "Maria"
"мария".capitalize #=> мария

Problem w tym, że po prostu nie robi tego, czego chcesz, марияzamiast tego wyświetla Мария.

Jeśli używasz Railsów, możesz łatwo obejść ten problem:

"мария".mb_chars.capitalize.to_s # requires ActiveSupport::Multibyte

W przeciwnym razie musisz zainstalować klejnot Unicode i używać go w następujący sposób:

require 'unicode'

Unicode::capitalize("мария") #=> Мария

Ruby 1.8:

Pamiętaj, aby użyć magicznego komentarza do kodowania :

#!/usr/bin/env ruby

puts "мария".capitalize

daje invalid multibyte char (US-ASCII), podczas gdy:

#!/usr/bin/env ruby
#coding: utf-8

puts "мария".capitalize

działa bez błędów, ale zobacz także sekcję „Ruby 2.3 i starsze”, aby zobaczyć prawdziwe wielkie litery.

Alberto Santini
źródło
21
Zauważ, że najwyraźniej "my API is great".capitalizespowoduje to, My api is greatco prawdopodobnie jest niepożądanym zachowaniem. Więc ta odpowiedź tak naprawdę nie odpowiada na pytanie, ponieważ chce tylko, aby PIERWSZA litera została zamieniona na wielką, a inne nietknięte.
Daniel AR Werner
55

wielką literą pierwszego słowa ciągu

"kirk douglas".capitalize
#=> "Kirk douglas"

wielką literą każdego słowa

W szynach:

"kirk douglas".titleize
=> "Kirk Douglas"

LUB

"kirk_douglas".titleize
=> "Kirk Douglas"    

W rubinie:

"kirk douglas".split(/ |\_|\-/).map(&:capitalize).join(" ") 
#=> "Kirk Douglas"

poza szynami, ale nadal chcąc użyć metody titleize

require 'active_support/core_ext'
"kirk douglas".titleize #or capitalize
boulder_ruby
źródło
1
Głosuj za czystym rozwiązaniem Ruby. Zbyt leniwy, żeby odpalić Railsy, ​​a to
załatwiło sprawę
19

Niestety, maszyna nie może poprawnie zmieniać / zmniejszać / zmniejszać wielkich liter. Potrzebuje zbyt wiele informacji kontekstowych, aby komputer mógł je zrozumieć.

Dlatego Stringklasa Rubiego obsługuje tylko wielkie litery w znakach ASCII, ponieważ jest tam przynajmniej dość dobrze zdefiniowana.

Co rozumiem przez „informacje kontekstowe”?

Na przykład, aby ipoprawnie pisać wielkimi literami , musisz wiedzieć, w jakim języku jest tekst. Na przykład angielski ma tylko dwa znaki i: duże Ibez kropki i małe iz kropką. Ale turecki ma cztery is: kapitał Ibez kropki, kapitał İz kropką, mały ıbez kropki, mały iz kropką. Tak więc w języku angielskim 'i'.upcase # => 'I'i tureckim 'i'.upcase # => 'İ'. Innymi słowy: ponieważ 'i'.upcasemoże zwrócić dwa różne wyniki, w zależności od języka, oczywiście niemożliwe jest poprawne zapisanie słowa z dużej litery bez znajomości języka.

Ale Ruby nie zna języka, zna tylko kodowanie. Dlatego niemożliwe jest poprawne zapisanie wielkiej litery w ciągu z wbudowaną funkcjonalnością Rubiego.

Sytuacja pogarsza się: nawet przy znajomości języka czasami niemożliwe jest prawidłowe wpisanie wielkich liter. Na przykład w języku niemieckim 'Maße'.upcase # => 'MASSE'( Maße to liczba mnoga od pomiaru znaczenia Maß ). Jednak (oznacza masę ). Więc co to jest ? Innymi słowy: prawidłowe kapitalizowanie wymaga pełnej sztucznej inteligencji.'Masse'.upcase # => 'MASSE''MASSE'.capitalize

Tak więc, zamiast czasami daje złą odpowiedź, Ruby zdecyduje się czasami nie dają odpowiedź na wszystko , dlatego znaki spoza ASCII prostu ignorowany w downcase / konwersji małych liter / wykorzystać operacje. (Co oczywiście prowadzi do błędnych wyników, ale przynajmniej łatwo to sprawdzić.)

Jörg W Mittag
źródło
4
Przepraszam, ale twoja argumentacja nie ma sensu. Nie jest prawdą, że Ruby w ogóle nie chce udzielać odpowiedzi, Ruby zawsze daje odpowiedź, która często jest błędna - np. „Мария” .upcase nie powinien nigdy zwracać „мария”, co nie jest poprawne w żadnym kontekście. A twoje dygresje na temat potrzeby sztucznej inteligencji w ogóle nie mają znaczenia - nic nie stoi na przeszkodzie, aby zachować tablicę z użyciem wielkich liter, powiedz [„I”, „İ”] zamiast „i”. w danej sytuacji. Obecnie Ruby obsługuje konwersję między dużymi i małymi literami i to wszystko.
michau
2
-1, ponieważ istnieje duże Eszett . Wykorzystanie jakiegoś niezupełnie sformalizowanego obszaru nie może świadczyć o tym, że rozwiązanie jest możliwe tylko w przypadku AI.
Mike
17

Cóż, tylko po to, abyśmy wiedzieli, jak skapitalizować tylko pierwszą literę, a resztę zostawić w spokoju, ponieważ czasami jest to pożądane:

['NASA', 'MHz', 'sputnik'].collect do |word|
  letters = word.split('')
  letters.first.upcase!
  letters.join
end

 => ["NASA", "MHz", "Sputnik"]

Połączenie capitalizespowoduje ["Nasa", "Mhz", "Sputnik"].

Huliax
źródło
Dziękuję tylko tego, czego szukałem, przydatne do konwersji nagłówków na
Good Lux
2
word[0] = word[0].upcase
David
@David. NIE! To zmienia wartości słów w tablicy, do której jest wywoływana #collect. To zły efekt uboczny.
Huliax
Pokazałem prostszy sposób kapitalizacji pierwszej litery słowa, zastępując wewnętrzne 3 wiersze tego rozwiązania, co wyjaśniłem, używając wordzmiennej. Oczywiście, jeśli masz więcej słów, po prostu zadzwoń do nich wszystkich! ;)words.map{|word| word[0] = word[0].upcase}
David
@David. Twój kod jest równy #capitalize!i nie #capitalize. Ta ostatnia zwraca nowy ciąg, podczas gdy pierwsza modyfikuje adresata metody (w tym przypadku odbiornikiem jest, worda metoda jest #[]). Jeśli użyjesz swojego kodu wewnątrz bloku #collect, otrzymasz dwie różne tablice z tymi samymi obiektami typu String w każdej z nich (a Strings zostałyby zmodyfikowane). To nie jest coś, co normalnie chciałbyś zrobić. Nawet jeśli jesteś tego świadomy, inni czytelnicy powinni to zrozumieć.
Huliax
12

Szyny 5+

Od Active Support i Rails 5.0.0.beta4 możesz użyć jednej z dwóch metod: String#upcase_firstlub ActiveSupport::Inflector#upcase_first.

"my API is great".upcase_first #=> "My API is great"
"мария".upcase_first           #=> "Мария"
"мария".upcase_first           #=> "Мария"
"NASA".upcase_first            #=> "NASA"
"MHz".upcase_first             #=> "MHz"
"sputnik".upcase_first         #=> "Sputnik"

Sprawdź " Rails 5: Nowa metoda upcase_first ", aby uzyskać więcej informacji.

user1519240
źródło
3

Użyj capitalize. Z dokumentacji String :

Zwraca kopię str z pierwszym znakiem zamienionym na wielką, a pozostałą na małą.

"hello".capitalize    #=> "Hello"
"HELLO".capitalize    #=> "Hello"
"123ABC".capitalize   #=> "123abc"
jhwist
źródło
Użyj wykrzyknika tylko wtedy, gdy chcesz zmienić oryginalny ciąg.
Magnar,
doh Dzięki, naprawiłem mój błąd.
jhwist
5
-1. OP wyraźnie wymienia tekst w języku niemieckim i rosyjskim, co oznacza znaki spoza ASCII. String#upcase(a także String#downcase) są zdefiniowane tylko dla znaków ASCII.
Jörg W Mittag,
1
Używam dziś Ruby 2.5.0 i String#upcasewydaje się, że działa dobrze na znakach spoza ASCII. 2.5.0 :001 > "мария".upcase => "МАРИЯ"
Huliax
1
@Huliax Jak wspomniano w zaakceptowanej odpowiedzi, tak było dopiero od czasu Ruby 2.4.0 (który został wydany w 2016 roku).
nisetama
2

Możesz użyć mb_chars. To szanuje umlaut:

class String

  # Only capitalize first letter of a string
  def capitalize_first
    self[0] = self[0].mb_chars.upcase
    self
  end

end

Przykład:

"ümlaute".capitalize_first
#=> "Ümlaute"
phlegx
źródło
2

Poniżej znajduje się inny sposób zapisania każdego słowa w ciągu wielkimi literami. \wnie dopasowuje cyrylicy ani znaków łacińskich ze znakami diakrytycznymi, ale [[:word:]]tak. upcase, downcase, capitalize, I swapcasenie stosuje się do znaków spoza ASCII aż Ruby 2.4.0, która została wydana w 2016 roku.

"aAa-BBB ä мария _a a_a".gsub(/\w+/,&:capitalize)
=> "Aaa-Bbb ä мария _a A_a"
"aAa-BBB ä мария _a a_a".gsub(/[[:word:]]+/,&:capitalize)
=> "Aaa-Bbb Ä Мария _a A_a"

[[:word:]] dopasowuje znaki z tych kategorii:

Ll (Letter, Lowercase)
Lu (Letter, Uppercase)
Lt (Letter, Titlecase)
Lo (Letter, Other)
Lm (Letter, Modifier)
Nd (Number, Decimal Digit)
Pc (Punctuation, Connector)

[[:word:]]pasuje do wszystkich 10 znaków z kategorii „Interpunkcja, łącznik” ( Pc):

005F _ LOW LINE
203F ‿ UNDERTIE
2040 ⁀ CHARACTER TIE
2054 ⁔ INVERTED UNDERTIE
FE33 ︳ PRESENTATION FORM FOR VERTICAL LOW LINE
FE34 ︴ PRESENTATION FORM FOR VERTICAL WAVY LOW LINE
FE4D ﹍ DASHED LOW LINE
FE4E ﹎ CENTRELINE LOW LINE
FE4F ﹏ WAVY LOW LINE
FF3F _ FULLWIDTH LOW LINE

Jest to inny sposób konwersji tylko pierwszego znaku ciągu na wielką literę:

"striNG".sub(/./,&:upcase)
=> "StriNG"
nisetama
źródło