วิธีการแปลงสตริงเป็น Title Case ใน Python


97

ตัวอย่าง:

HILO -> Hilo
new york -> New York
SAN FRANCISCO -> San Francisco

มีไลบรารีหรือวิธีมาตรฐานในการทำงานนี้หรือไม่?


16
นั่นไม่ใช่ "CamelCase" นั่นคือ "Capitalize"; คุณต้องการแบบไหน?
Andrew Marshall

13
camelCase เป็นแบบนี้
Jonathan M

5
ตัวอย่างของคุณใช้ PascalCase
David Betz

คำตอบ:


219

ทำไมไม่ใช้titleRight from the docs:

>>> "they're bill's friends from the UK".title()
"They'Re Bill'S Friends From The Uk"

หากคุณต้องการ PascalCase จริงๆคุณสามารถใช้สิ่งนี้:

>>> ''.join(x for x in 'make IT pascal CaSe'.title() if not x.isspace())
'MakeItPascalCase'

5
ฉันคิดว่าตัว 'r' ใน "พวกเขา" ควรเป็นตัวพิมพ์เล็ก และของใน "Bill's" ต้องเป็นตัวพิมพ์เล็ก
Daniel Fischer

3
@ แดเนียล - ปัญหานั้นถูกบันทึกไว้ในเอกสารสำหรับtitle: "อัลกอริทึมใช้คำจำกัดความของคำที่ไม่ขึ้นกับภาษาเป็นกลุ่มของตัวอักษรที่ต่อเนื่องกันคำจำกัดความใช้ได้ในหลายบริบท แต่หมายความว่าเครื่องหมายอะพอสทรอฟีในการหดตัวและการเป็นเจ้าของทำให้เกิดขอบเขตคำ ซึ่งอาจไม่ใช่ผลลัพธ์ที่ต้องการ ". ทางออกหนึ่งที่เป็นไปได้คือใช้คำตอบของ Laurence กับ regex r"['\w]+"เพื่อไม่ให้เครื่องหมายวรรคตอนจบการแข่งขัน (สามารถเพิ่มเครื่องหมายวรรคตอนเพิ่มเติมได้ตามต้องการ)
Andrew Clark

18
สำหรับบันทึกที่เป็นวิธี neater ที่จะทำเช่น CamelCase 'make IT camel CaSe'.title().replace(' ', '')ที่ผ่านมาเป็น
Henry Gomersall

15
หากใครก็ตามที่รู้สึกว่าพวกเขากำลังใช้ยาบ้านี่คือ PascalCase ไม่ใช่ camelCase
ร็อบ

4
รหัสที่ดี แต่ camelCase ไม่ได้ขึ้นต้นด้วย CAPITAL ลองสิ่งนี้: def toCamel(s): ret = ''.join(x for x in s.title() if not x.isspace()) return ret[0].lower() + ret[1:] การใช้งาน:toCamel("WRITE this in camelcase") 'writeThisInCamelcase'
Ron Kalian

22

อันนี้จะขึ้นต้นด้วยตัวพิมพ์เล็กเสมอและแถบอักขระที่ไม่ใช่ตัวเลขและตัวอักษร:

def camelCase(st):
    output = ''.join(x for x in st.title() if x.isalnum())
    return output[0].lower() + output[1:]

8
def capitalizeWords(s):
  return re.sub(r'\w+', lambda m:m.group(0).capitalize(), s)

re.subสามารถใช้ฟังก์ชันสำหรับ "การแทนที่" (แทนที่จะเป็นเพียงสตริงซึ่งเป็นการใช้งานที่คนส่วนใหญ่ดูเหมือนจะคุ้นเคย) ฟังก์ชันการจำลองนี้จะถูกเรียกด้วยre.Matchออบเจ็กต์สำหรับการจับคู่แต่ละรูปแบบและผลลัพธ์ (ซึ่งควรเป็นสตริง) จะถูกใช้แทนการจับคู่นั้น

เวอร์ชันที่ยาวกว่าของสิ่งเดียวกัน:

WORD_RE = re.compile(r'\w+')

def capitalizeMatch(m):
  return m.group(0).capitalize()

def capitalizeWords(s):
  return WORD_RE.sub(capitalizeMatch, s)

สิ่งนี้รวบรวมรูปแบบไว้ล่วงหน้า (โดยทั่วไปถือว่าเป็นรูปแบบที่ดี) และใช้ฟังก์ชันที่ตั้งชื่อแทนแลมบ์ดา


อันนี้สวยเนี๊ยบฉันพยายามเอาหัวไปเกี่ยวกับฟังก์ชั่นแลมด้าขอบคุณที่ช่วย
ฝันกลางวัน

1
@JohnMachin ฉันถามเพราะคิดว่าการเพิ่มคำอธิบายจะทำให้คำตอบของคุณสมบูรณ์และดีขึ้น
NN

@Laurence Gonsalves แลมด้ามาทำอะไรที่นี่?
Zion

แลมด้ามาทำอะไรที่นี่? จากที่ฉันสามารถถอดรหัสและจากคำอธิบายของคุณ นี่คือสิ่งที่ฉันเข้าใจ เมื่อคุณใช้ฟังก์ชันใน re.sub แต่ละฟังก์ชันmatchจะถูกส่งผ่านไปยังฟังก์ชัน? และเนื่องจากmatchesในนิพจน์ทั่วไปมีกลุ่ม นั่นคือเหตุผลที่มีบรรทัดนี้lambda m:m.group(0).capitalize()?
Zion

@ ไซออนใช่ เมื่อre.subได้รับการเรียก (เช่นฟังก์ชัน) เป็น "การแทนที่" จะส่งผ่านวัตถุที่ตรงกันไปยังที่เรียกได้และคาดว่าจะได้รับสตริงกลับซึ่งเป็นสิ่งที่ใช้แทนได้จริง หากคุณพบว่า lambdas สับสน "เวอร์ชันที่ยาวขึ้น" จะทำสิ่งเดียวกันทุกประการในลักษณะที่ละเอียดกว่า
Laurence Gonsalves

5

ทำไมไม่เขียนล่ะ สิ่งนี้อาจตอบสนองความต้องการของคุณ:

def FixCase(st):
    return ' '.join(''.join([w[0].upper(), w[1:].lower()]) for w in st.split())

ขอบคุณที่ช่วยได้อย่างสมบูรณ์ แย่จังฉันไม่คิดจะเขียนตั้งแต่แรก
ฝันกลางวัน

5

หมายเหตุ: เหตุใดฉันจึงให้คำตอบอื่น คำตอบนี้ขึ้นอยู่กับชื่อของคำถามและแนวคิดที่ว่า camelcase ถูกกำหนดให้เป็น: ชุดคำที่เรียงต่อกัน (ไม่เว้นวรรค!) โดยที่คำดั้งเดิมแต่ละคำขึ้นต้นด้วยอักษรตัวใหญ่ (ส่วนที่เหลือเป็นตัวพิมพ์เล็ก) ยกเว้นคำแรกของชุด (ซึ่งเป็นตัวพิมพ์เล็กทั้งหมด) นอกจากนี้ยังสันนิษฐานว่า "สตริงทั้งหมด" หมายถึงชุดอักขระ ASCII; Unicode จะใช้ไม่ได้กับโซลูชันนี้)

เรียบง่าย

ด้วยคำจำกัดความข้างต้นฟังก์ชันนี้

import re
word_regex_pattern = re.compile("[^A-Za-z]+")

def camel(chars):
  words = word_regex_pattern.split(chars)
  return "".join(w.lower() if i is 0 else w.title() for i, w in enumerate(words))

เมื่อถูกเรียกจะส่งผลในลักษณะนี้

camel("San Francisco")  # sanFrancisco
camel("SAN-FRANCISCO")  # sanFrancisco
camel("san_francisco")  # sanFrancisco

เรียบง่ายน้อยลง

โปรดทราบว่าจะล้มเหลวเมื่อนำเสนอด้วยเชือกที่หุ้มอูฐอยู่แล้ว

camel("sanFrancisco")   # sanfrancisco  <-- noted limitation

เรียบง่ายแม้แต่น้อย

โปรดทราบว่าล้มเหลวด้วยสตริง Unicode จำนวนมาก

camel("México City")    # mXicoCity     <-- can't handle unicode

ฉันไม่มีวิธีแก้ปัญหาสำหรับกรณีเหล่านี้ (หรืออย่างอื่นที่สามารถนำมาใช้กับความคิดสร้างสรรค์) ดังนั้นในทุกสิ่งที่เกี่ยวข้องกับสตริงให้ครอบคลุมเคสขอบของคุณเองและขอให้โชคดีกับ Unicode!


คุณจะตรวจสอบได้อย่างไรว่าสตริงคือตัวอักษร Camel โดยไม่ทราบความหมายของประโยค? ในตัวอย่าง "ง่ายน้อยกว่า" ของคุณ "sanfRancisco" คือ Camel case และ "itSnotcaMelcAse"
Patrice Bernassola

ฉันเดาว่าข้อมูลของคุณมีข้อความแสดงความคิดเห็นหรือเครื่องหมายวรรคตอนอื่น ๆ ? ฉันควรสังเกตการป้อนข้อมูลอื่นที่ล้มเหลว จับได้ดีแน่นอน อินพุตที่คุณระบุคืออะไร?
Marc

1
ฉันหมายถึงลำดับของอักขระที่ไม่มีช่องว่างต้องพิจารณาเป็น 1 คำ คุณไม่สามารถแยกงานจากมันโดยไม่ทราบความหมายของประโยค ใส่ "sanfRancisco" หรือ "itSnotcaMelcAse" เป็นอินพุตของ camello () และคุณจะเห็นว่าเอาต์พุตจะเหมือนกัน
Patrice Bernassola

โอ้ฉันเข้าใจ - ใช่ฉันคิดว่าคุณพูดถูก ฉันใช้วิธีแก้ปัญหามากเกินไป ฉันจะอัปเดตให้
Marc

4

ห้องสมุดที่มีศักยภาพ: https://pypi.org/project/stringcase/

ตัวอย่าง:

import stringcase
stringcase.camelcase('foo_bar_baz') # => "fooBarBaz"

แม้ว่าจะเป็นที่น่าสงสัยว่าจะเว้นช่องว่างไว้หรือไม่ (ตัวอย่างแสดงให้เห็นว่าการลบช่องว่างออก แต่มีปัญหาตัวติดตามข้อผิดพลาดที่สังเกตว่ามันทิ้งไว้


ห่าใช่ กำลังมองหาแพ็คเกจ แพ็คเกจนี้มี Snakecase และฟังก์ชันการแปลงอื่น ๆ ด้วย
s2t2

1

เพียงแค่ใช้ .title () และมันจะแปลงตัวอักษรตัวแรกของทุกคำเป็นตัวพิมพ์ใหญ่โดยวางตัวเป็นตัวเล็ก:

>>> a='mohs shahid ss'
>>> a.title()
'Mohs Shahid Ss'
>>> a='TRUE'
>>> b=a.title()
>>> b
'True'
>>> eval(b)
True

1

ฉันต้องการเพิ่มผลงานเล็กน้อยของฉันในโพสต์นี้:

def to_camelcase(str):
  return ' '.join([t.title() for t in str.split()])

จริงๆแล้ว str.title () ก็เหมือนกันและคุณกำลังประหยัดค่าใช้จ่ายในการคำนวณ
Auros132

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.