Zapisać wielką literę tylko pierwszy znak ciągu, a inne zostawić w spokoju? (Szyny)

102

Próbuję zmusić Railsy do zapisania wielkimi literami pierwszego znaku ciągu i pozostawienia wszystkich innych takimi, jakie są. Mam problem, w wyniku którego „Jestem z Nowego Jorku” zamienia się w „Jestem z Nowego Jorku”.

Jakiej metody użyłbym, aby wybrać pierwszy znak?

Dzięki

EDYCJA: Próbowałem zaimplementować to, co zasugerował macek, ale otrzymuję błąd „niezdefiniowana metoda„ używać wielkich liter ” . Kod działa dobrze bez wiersza z wielką literą. Dzięki za pomoc!

def fixlistname!
  self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...")
  self.title[0] = self.title[0].capitalize
  errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with? 'You know you'
end

EDYCJA 2: Działa. Dzięki za pomoc!

EDYCJA 3: Czekaj, nie, nie ... Oto, co mam w moim modelu listy.

def fixlistname!
  self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...")
  self.title.slice(0,1).capitalize + self.title.slice(1..-1)
  errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with?  'You know you'
end

EDYCJA 4: Wypróbowałem edycję macek, ale nadal otrzymuję błąd wielkiej ” metody w niezdefiniowanej metodzie . Co mogę zrobić źle?

def fixlistname!
  self.title = title.lstrip
  self.title += '...' unless title.ends_with?('...')
  self.title[0] = title[0].capitalize
  errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you")
end

EDYCJA 5: To dziwne. Jestem w stanie pozbyć się niezdefiniowanego błędu metody, korzystając z poniższej linii. Problem w tym, że zdaje się zastępować pierwszą literę liczbą. Na przykład, zamiast pisać wielką literę y w tobie , zamienia y w 121

self.title[0] = title[0].to_s.capitalize
Daniel O'Connor
źródło
W oparciu o EDIT 3, musisz zacząć linię 2 od self.title = . Ponadto we wszystkich 3 liniach wystarczy self.titlepo lewej stronie =(znak równości). W innych miejscach możesz po prostu użyć title. Zobacz przykład w mojej odpowiedzi.
maček
2
Problem w Edit4 polega na tym, że masz tylko znak - nie jest to już ciąg znaków - dlatego nie rozpoznaje on funkcji ciągu znaków „capitalize”.
Taryn East
Problem z Edit 5 polega na tym, że title [0] jest poprawką, więc wywołanie title [0] .to_s da ci tylko numer znaku (tj. 121 jako ciąg: "121"). Jeśli chcesz, możesz zrobić self.title [0] = title.first.capitalize!
Nick
Dodałem #upcase_first_case i wysłałem żądanie ściągnięcia: github.com/rails/rails/pull/15319 . Możesz tam dodać swoją opinię.
Aldo 'xoen' Giambelluca

Odpowiedzi:

93

W Titleize każde słowo będzie wielką literą. Ta linia wydaje się mocna, ale gwarantuje, że jedyna zmieniona litera jest pierwszą.

new_string = string.slice(0,1).capitalize + string.slice(1..-1)

Aktualizacja:

irb(main):001:0> string = "i'm from New York..."
=> "i'm from New York..."
irb(main):002:0> new_string = string.slice(0,1).capitalize + string.slice(1..-1)
=> "I'm from New York..."
Taryn East
źródło
Czekaj, nadal nie działa. Fałszywy alarm: / Myślę, że po prostu źle go implementuję.
Daniel O'Connor
1
Daniel - generalnie jest to dobra forma „zaakceptowania” odpowiedzi, która rozwiązała twój problem. Możesz to zrobić, klikając „ptaszek” po lewej stronie odpowiedzi. :)
Taryn East
1
Źle zrozumiałem pytanie, w przeciwnym razie chciałem dać ci 1. Szukałem .titleize zamiast .capitalize. W każdym razie dziękuję Taryn!
Eric Wanchic
OOC - Dlaczego to powstrzymuje Cię przed oddaniem głosu za? Czy poprawnie odpowiedziałem na pytanie pierwotnego autora? Jeśli tak uważasz - zagłosuj za. Nie musi być uzależnione od niczego innego ... :)
Taryn East
2
Tak więc, oto idzie: s[0].capitalize + s[1..-1] if s.present?
Alex Escalante
126

To powinno wystarczyć:

title = "test test"     
title[0] = title[0].capitalize
puts title # "Test test"
Pascal Van Hecke
źródło
40
Lub bardziej zwięźletitle[0] = title[0].capitalize
Jon Garvin,
To bardzo eleganckie rozwiązanie.
Karew
1
@JonGarvin tytuł [0] .capitalize nie działa (przynajmniej z Ruby 1.8.7), ponieważ title [0] zwraca Fixnum, a wielkie litery oczekuje ciągu znaków .. więc myślę, że title.first.capitalize to sposób na udać się.
Nick
2
szkoda, że ​​nie możesztitle.first.capitalize!
Adam Waite
1
capitalizekonwertuje wszystkie litery po pierwszej literze na małe, więc nie działa dla ciągu przedstawionego w pytaniu („Jestem z Nowego Jorku”).
Mark Schneider
57

Możesz użyć humanizacji. Jeśli nie potrzebujesz podkreśleń ani innych wielkich liter w liniach tekstu.

Wejście:

"i'm from New_York...".humanize

Wynik:

"I'm from new york..."
Bartuzz
źródło
7
OP szczególnie chciał uniknąć „Nowego Jorku”
phatmann
Hmm rzeczywiście, trochę za szybko z moją odpowiedzią.
Bartuzz,
17
@Bartuzz Mimo że OP nie tego chciał, to jest dokładnie to, czego szukałem. Dzięki!
Yetti,
Nowy jork byłby jednak niegramatyką jako jego nazwa własna i powinien używać wielkich liter.
Shayne
Ostrzegam, humanizejest Rails, dokładnie metoda ActiveSupport. Zwykły rubin nie może tego zrobić.
Penguin
51
str = "this is a Test"
str.sub(/^./, &:upcase)
# => "This is a Test"
Lasse Bunk
źródło
1
Zwięzły i elegancki. Uważam, że to powinna być najlepsza odpowiedź.
Chris,
Zgadzam się. Myślę, że to powinna być akceptowana odpowiedź.
Garry Pettet
Jednym z dziwactw jest to, że skoro ^oznacza początek linii, "\nfoo"staje się "\nFoo". To prawdopodobnie w porządku w większości przypadków użycia. Ponieważ jest to suba nie a gsub, to nadal będzie tylko jedna litera, nawet w przypadku ciągów wielowierszowych.
Henrik N
Powyższe ograniczenie można uzyskać str.sub(/\S/, &:upcase), używając polecenia , które znajdzie pierwszy znak niebędący białą spacją i zapisze go w górę.
Anthony Panozzo
39

Od wersji Rails 5.0.0.beta4 możesz użyć nowej String#upcase_firstmetody lub ActiveSupport::Inflector#upcase_firstto zrobić. Więcej informacji znajdziesz w tym poście na blogu .

user1519240
źródło
To wspaniała wiadomość! Zastanawiałem się, co możemy teraz zrobić i może polyfill dla Rails 4 byłby fajny.
hakunin
Zauważ, że upcase_first i nie obsługuje akcentów / znaków specjalnych, nawet z mb_chars
user3033467
14

Rozwiązanie zorientowane obiektowo:

class String
  def capitalize_first_char
    self.sub(/^(.)/) { $1.capitalize }
  end
end

Następnie możesz po prostu zrobić to:

"i'm from New York".capitalize_first_char
lmanners
źródło
Przynajmniej ktoś napisał eleganckie rozwiązanie z rozszerzeniem Stringklasy.
Dmitriy
@Dmitriy dlaczego małpa łata klasę stringów elegancko?
Gerard Simpson
7
str.sub(/./, &:capitalize)
emlai
źródło
6

Edytuj 2

Nie mogę powtórzyć twojego kłopotu. Śmiało i uruchom ten natywny skrypt Ruby. Generuje dokładnie takie wyjście, jakiego szukasz, a Railsy obsługują wszystkie te metody. Z jakim rodzajem danych wejściowych masz problem?

#!/usr/bin/ruby
def fixlistname(title)
  title = title.lstrip
  title += '...' unless title =~ /\.{3}$/
  title[0] = title[0].capitalize
  raise 'Title must start with "You know you..."' unless title =~ /^You know you/
  title
end

DATA.each do |title|
  puts fixlistname(title)
end

__END__
you know you something WITH dots ...
you know you something WITHOUT the dots
  you know you something with LEADING whitespace...
  you know you something with whitespace BUT NO DOTS
this generates error because it doesn't start with you know you

wynik

You know you something WITH dots ...
You know you something WITHOUT the dots...
You know you something with LEADING whitespace...
You know you something with whitespace BUT NO DOTS...
RuntimeError: Title must start with "You know you..."

Edytować

W oparciu o swoją zmianę możesz spróbować czegoś takiego.

def fixlistname!
  self.title = title.lstrip
  self.title += '...' unless title.ends_with?('...')
  self.title[0] = title[0].capitalize
  errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you")
end

Oryginalny

To wystarczy

s = "i'm from New York"
s[0] = s[0].capitalize
#=> I'm from New York

Podczas próby użycia String#capitalizena całym ciągu, zobaczyłeś, I'm from new yorkponieważ metoda:

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

"hello".capitalize    #=> "Hello"
"HELLO".capitalize    #=> "Hello"
"123ABC".capitalize   #=> "123abc"
maček
źródło
+1 ponieważ nie sądziłem, że to zadziała, dopóki nie
wypróbuję
Cześć, dzięki za pomoc. Co ja jednak robię źle? Zmodyfikowałem oryginalne pytanie, aby uwzględnić mój kod.
Daniel O'Connor
Skorzystałem z sugestii Taryn i sprawiłem, że zadziałało. Ale dzięki za pomoc!
Daniel O'Connor
Cześć, stackoverflow mówi, że dokonałeś zmiany, ale nie widzę nic innego?
Daniel O'Connor
6
my_string = "hello, World"
my_string.sub(/\S/, &:upcase) # => "Hello, World"
Pavel Pravosud
źródło
Nie zawiedzie, jeśli my_string jest pusty! Miły. To jest to, czego potrzebuję.
Huliax
4

Większość z tych odpowiedzi edytuje ciąg w miejscu, kiedy tylko formatujesz dane wyjściowe, możesz nie chcieć zmieniać podstawowego ciągu, więc możesz użyć tappo a, dupaby uzyskać edytowaną kopię

'test'.dup.tap { |string| string[0] = string[0].upcase }
Paul.s
źródło
3

Jeśli i tylko wtedy, gdy OP chciałby wykonać małpią poprawkę na obiekcie String, można tego użyć

class String
  # Only capitalize first letter of a string
  def capitalize_first
    self.sub(/\S/, &:upcase)
  end
end

Teraz użyj:

"i live in New York".capitalize_first #=> I live in New York
JVK
źródło
2

Jeszcze krótsza wersja mogłaby wyglądać następująco:

s = "i'm from New York..."
s[0] = s.capitalize[0]
Saim
źródło
2

Nikt nie wspomniał o gsub, co pozwala to zrobić zwięźle.

string.gsub(/^([a-z])/) { $1.capitalize }

Przykład:

 > 'caps lock must go'.gsub(/^(.)/) { $1.capitalize }
=> "Caps lock must go"
mahemoff
źródło
1

Być może najłatwiejszy sposób.

s = "test string"
s[0] = s[0].upcase
# => "Test string"
Lukas Baliak
źródło
1

Pamiętaj, że jeśli musisz radzić sobie ze znakami wielobajtowymi, tj. Jeśli musisz umiędzynarodowić swoją witrynę, s[0] = ...rozwiązanie nie będzie odpowiednie. To pytanie dotyczące przepełnienia stosu sugeruje użycie klejnotu unicode-util

Ruby 1.9: w jaki sposób mogę odpowiednio zmienić wielkość i małe litery na łańcuchy wielobajtowe?

EDYTOWAĆ

Właściwie łatwiejszym sposobem przynajmniej uniknięcia dziwnego kodowania ciągów jest po prostu użycie String # mb_chars :

s = s.mb_chars
s[0] = s.first.upcase
s.to_s
frontendbeauty
źródło
0

A co z klasyfikacją metody na łańcuchu?

'somESTRIng'.classify

wynik:

#rails => 'SomESTRIng'
mArtinko5MB
źródło
1
Robi wiele dodatkowych rzeczy, takich jak wyróżnianie słów. "hello worlds".classify # => "Hello world"
Pavel Pravosud
-3
string = "i'm from New York"
string.split(/\s+/).each{ |word,i| word.capitalize! unless i > 0 }.join(' ')
# => I'm from New York
Jeriko
źródło
Na to wygląda. Jestem nowy w Ruby, a inne odpowiedzi nie były zgodne z oczekiwaniami OP, więc udało mi się: D Popraw mnie, jeśli się mylę, ale AFAIK modyfikacja ciągu poprzez zmianę ciągu [i] nie działa pracujesz w wielu językach?
Jeriko
3
to jest pytanie specyficzne dla Rubiego. Nie ma znaczenia, czy string[i]nie działa w innych językach. Pomóż zachować porządek w usłudze StackOverflow bez bałaganu związanego z tego rodzaju zhakowanymi odpowiedziami. Nie możemy powiedzieć RTFM, ale nawet szybkie spojrzenie na Stringdokumentację pomogłoby uniknąć takiej odpowiedzi ...
maček