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

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..."

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"

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..."

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"

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 .


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

Przynajmniej ktoś napisał eleganckie rozwiązanie z rozszerzeniem Stringklasy.
Dmitriy

@Dmitriy dlaczego małpa łata klasę stringów elegancko?
Gerard Simpson


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"

+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"

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 }

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

2

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

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

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"

1

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

s = "test string"
s[0] = s[0].upcase
# => "Test string"

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

0

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

'somESTRIng'.classify

wynik:

#rails => 'SomESTRIng'

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.