एक स्ट्रिंग के पहले अक्षर को कैपिटल में क्यों डाला जाता है?


82

मैं पहले अक्षर का कैपिटलाइज़ करना चाहता हूँ &str। यह एक साधारण समस्या है और मैं एक सरल समाधान की उम्मीद करता हूं। अंतर्ज्ञान मुझे ऐसा कुछ करने के लिए कहता है:

let mut s = "foobar";
s[0] = s[0].to_uppercase();

लेकिन &strइस तरह अनुक्रमित नहीं किया जा सकता है। एक ही रास्ता है कि मैं ऐसा करने में सक्षम हो गया है अत्यधिक संतुष्ट लगता है। मैं &strएक पुनरावृत्त में परिवर्तित करता हूं , पुनरावृत्ति को एक सदिश में परिवर्तित करता हूं , ऊपरी स्थिति सदिश में पहला आइटम है, जो एक पुनरावृत्ति बनाता है, जिसे मैं अनुक्रमित करता हूं, एक निर्माण Optionकरता हूं, जिसे मैं अपर-केसेड पहला अक्षर देने के लिए तैयार करता हूं। फिर मैं वेक्टर को पुनरावृत्त में परिवर्तित करता हूं, जिसे मैं एक में परिवर्तित करता हूं, जिसे मैं एक में परिवर्तित Stringकरता हूं &str

let s1 = "foobar";
let mut v: Vec<char> = s1.chars().collect();
v[0] = v[0].to_uppercase().nth(0).unwrap();
let s2: String = v.into_iter().collect();
let s3 = &s2;

क्या इससे आसान तरीका है, और यदि हां, तो क्या है? यदि नहीं, तो रस्ट को इस तरह से क्यों बनाया गया है?

इसी तरह का सवाल


46
यह एक साधारण समस्या है - नहीं, यह नहीं है। कृपया ßजर्मन के रूप में व्याख्या करने पर कैपिटलाइज़ करें । संकेत: यह एक एकल चरित्र नहीं है। यहां तक ​​कि समस्या कथन जटिल हो सकता है। उदाहरण के लिए, उपनाम के पहले चरित्र को भुनाना अनुचित होगा von Hagen। यह एक वैश्विक दुनिया में रहने का एक पहलू है, जिसमें विभिन्न प्रथाओं के साथ हजारों वर्षों की विभिन्न संस्कृतियां हैं और हम उन सभी को 8 बिट्स और कोड की 2 पंक्तियों में स्क्वैश करने की कोशिश कर रहे हैं।
शमपास्टर

3
आपको जो लगता है वह एक चरित्र एन्कोडिंग समस्या है, डेटा प्रकार की समस्या नहीं है। मुझे लगता है कि चार :: पहले से ही ठीक से यूनिकोड संभालता है। मेरा सवाल है, सभी डेटा प्रकार रूपांतरणों की आवश्यकता क्यों है? ऐसा लगता है कि अनुक्रमण एक बहु-बाइट, यूनिकोड वर्ण (एक भी बाइट चरित्र नहीं है, जो केवल एससीआई मान सकता है) को वापस कर सकता है, और to_uppercase किसी भी मामले में ऊपरी मामले के चरित्र को वापस कर सकता है, चाहे वह किसी भी भाषा में उपलब्ध हो।
मार्शमैल

3
@marshallm char::to_uppercaseवास्तव में इस समस्या को संभालता है, लेकिन आप nth(0)इसके सभी कोड पॉइंट्स के बजाय केवल पहला कोड पॉइंट ( ) लेने की कोशिश करते हैं, जो कि कैपिटलाइज़ेशन बनाते हैं

चरित्र एन्कोडिंग एक सीधी प्रक्रिया नहीं है जैसा कि सॉफ्टवेयर पर जोएल ने बताया है : यूनिकोड
नाथन

@ शमस्टर, सामान्य तौर पर आप सही हैं। यह अंग्रेजी में एक सरल समस्या है (प्रोग्रामिंग भाषाओं और डेटा प्रारूपों का वास्तविक मानक आधार)। हां, ऐसी स्क्रिप्ट हैं जहां "कैपिटलाइज़ेशन" एक अवधारणा भी नहीं है, और अन्य जहां यह बहुत जटिल है।
पॉल ड्रेपर

जवाबों:


101

ऐसा क्यों होता है?

चलो इसे तोड़ दो, लाइन-बाय-लाइन

let s1 = "foobar";

हमने एक शाब्दिक स्ट्रिंग बनाया है जो UTF-8 में एन्कोडेड है । UTF-8 हमें यूनिकोड के 1,114,112 कोड पॉइंट्स को इस तरह से एनकोड करने की अनुमति देता है, जो कि बहुत कॉम्पैक्ट है यदि आप दुनिया के किसी ऐसे क्षेत्र से आते हैं, जो ज्यादातर ASCII में पाए जाने वाले वर्णों में टाइप करते हैं , 1963 में बनाया गया एक मानक। UTF-8 एक चर लंबाई है एन्कोडिंग, जिसका अर्थ है कि एक एकल कोड बिंदु 1 से 4 बाइट्स तक हो सकता है । छोटे एनकोडिंग ASCII के लिए आरक्षित हैं, लेकिन कई कांजी UTF-8 में 3 बाइट लेते हैं

let mut v: Vec<char> = s1.chars().collect();

यह charअभिनेताओं का एक वेक्टर बनाता है । एक चरित्र एक 32-बिट संख्या है जो सीधे एक कोड बिंदु पर मैप करता है। यदि हमने ASCII- केवल पाठ के साथ शुरुआत की है, तो हमने अपनी मेमोरी आवश्यकताओं को चौगुना कर दिया है। यदि हमारे पास सूक्ष्म विमान से वर्णों का एक समूह था , तो शायद हमने उसका अधिक उपयोग नहीं किया है।

v[0] = v[0].to_uppercase().nth(0).unwrap();

यह पहले कोड बिंदु को पकड़ता है और अनुरोध करता है कि इसे अपरकेस वैरिएंट में बदला जाए। दुर्भाग्य से हममें से जो अंग्रेजी बोलते हुए बड़े हुए हैं, वहां हमेशा "छोटे अक्षर" से "बड़े अक्षर" की मैपिंग एक-से-एक नहीं होती है । साइड नोट: हम उन्हें ऊपरी और निचले मामले कहते हैं, क्योंकि पत्रों का एक बॉक्स दिन में वापस पत्र के दूसरे बॉक्स के ऊपर था

जब कोड बिंदु के पास कोई अपरकेस संस्करण नहीं होगा तो यह कोड घबरा जाएगा। मुझे यकीन नहीं है कि अगर वे मौजूद हैं, तो वास्तव में। यह तब भी शब्दार्थ में विफल हो सकता है जब एक कोड बिंदु में एक अपरकेस वैरिएंट होता है जिसमें कई अक्षर होते हैं, जैसे कि जर्मन ß। ध्यान दें कि, वास्तव में कभी भी वास्तविक दुनिया में पूंजीकृत नहीं किया जा सकता है, यह केवल एक उदाहरण है जिसे मैं हमेशा याद रख सकता हूं और खोज सकता हूं। 2017/06/29 के रूप में, वास्तव में, जर्मन वर्तनी की आधिकारिक नियम तो अपडेट किए गए हों दोनों "ẞ" और "एसएस" वैध पूंजीकरण हैं !

let s2: String = v.into_iter().collect();

यहां हम वर्णों को वापस UTF-8 में परिवर्तित करते हैं और उन्हें स्टोर करने के लिए एक नए आवंटन की आवश्यकता होती है, क्योंकि मूल चर को निरंतर मेमोरी में संग्रहीत किया जाता था ताकि रन टाइम पर मेमोरी न खींची जा सके।

let s3 = &s2;

और अब हम इसका संदर्भ लेते हैं String

यह एक साधारण समस्या है

दुर्भाग्य से यह सच नहीं है। शायद हमें दुनिया को स्कॉर्पियो में बदलने का प्रयास करना चाहिए ?

मुझे लगता है कि char::to_uppercaseपहले से ही ठीक से यूनिकोड संभालता है।

हां, मैं निश्चित रूप से उम्मीद करता हूं। दुर्भाग्य से, यूनिकोड सभी मामलों में पर्याप्त नहीं है। के लिए धन्यवाद ओर इशारा करते हुए के लिए huon तुर्की मैं , जहां दोनों ऊपरी ( İ ) और लोअर केस ( मैं ) संस्करणों में एक बिंदु है। यही कारण है कि कोई नहीं है, है एक पत्र के समुचित पूंजीकरण i; यह स्रोत पाठ के स्थान पर भी निर्भर करता है ।

सभी डेटा प्रकार रूपांतरणों की आवश्यकता क्यों है?

क्योंकि आप जिस डेटा प्रकार के साथ काम कर रहे हैं वह महत्वपूर्ण है जब आप शुद्धता और प्रदर्शन के बारे में चिंतित हैं। A char32-बिट्स है और एक स्ट्रिंग UTF-8 एनकोडेड है। वे अलग चीजें हैं।

अनुक्रमण बहु-बाइट, यूनिकोड वर्ण लौटा सकता है

यहां कुछ बेमेल शब्दावली हो सकती है। एक char है एक मल्टी-बाइट यूनिकोड वर्ण।

टुकड़ा करने की क्रिया एक स्ट्रिंग यदि संभव हो तो आप बाइट-दर-बाइट जाते हैं, लेकिन यदि आप अक्षर सीमा पर नहीं हैं मानक पुस्तकालय आतंक जाएगा।

एक चरित्र प्राप्त करने के लिए एक स्ट्रिंग को अनुक्रमित करने के कारणों में से एक को कभी भी लागू नहीं किया गया था, क्योंकि बहुत से लोग ASIIII वर्णों के सरणियों के रूप में तारों का दुरुपयोग करते हैं। एक चरित्र को सेट करने के लिए एक स्ट्रिंग को अनुक्रमणित करना कभी भी कुशल नहीं हो सकता है - आपको 1-4 बाइट्स को एक मूल्य के साथ बदलने में सक्षम होना होगा जो कि 1-4 बाइट्स भी है, जिससे बाकी स्ट्रिंग काफी उछाल लेती है।

to_uppercase एक ऊपरी मामले के चरित्र को वापस कर सकता है

जैसा कि ऊपर उल्लेख किया गया है, ßएक एकल वर्ण है, जब पूंजीकृत होता है, दो वर्ण बन जाता है ।

समाधान

ट्रेंटक्ल का जवाब भी देखें जो केवल ASCII वर्णों को अपरकेस करता है।

मूल

अगर मुझे कोड लिखना था, तो यह ऐसा लगेगा:

fn some_kind_of_uppercase_first_letter(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().chain(c).collect(),
    }
}

fn main() {
    println!("{}", some_kind_of_uppercase_first_letter("joe"));
    println!("{}", some_kind_of_uppercase_first_letter("jill"));
    println!("{}", some_kind_of_uppercase_first_letter("von Hagen"));
    println!("{}", some_kind_of_uppercase_first_letter("ß"));
}

लेकिन मैं शायद crates.io पर अपरकेस या यूनिकोड की खोज करूंगा और किसी को मुझसे ज्यादा स्मार्ट बनाने के लिए इसे संभालने दूंगा।

उन्नत

"मुझसे ज्यादा होशियार किसी व्यक्ति" की बात करते हुए, वेद्रेक बताते हैं कि संभवत: पहला कैपिटल कोडपाइंट एक्सेस होने के बाद पुनरावृत्त को एक स्लाइस में बदलना अधिक कुशल है। यह memcpyबाइट्स के बाकी हिस्सों के लिए अनुमति देता है ।

fn some_kind_of_uppercase_first_letter(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}

34
इसके बारे में बहुत सोचने के बाद, मैं इन डिज़ाइन विकल्पों को बेहतर तरीके से समझता हूं। मानक पुस्तकालय को सबसे बहुमुखी, प्रदर्शनकारी और सुरक्षित व्यापार-नापसंद का चयन करना चाहिए। अन्यथा, यह डेवलपर्स को ऐसे ट्रेड-ऑफ बनाने के लिए मजबूर करता है जो उनके आवेदन, वास्तुकला या स्थान के लिए उपयुक्त नहीं हो सकते हैं। या इससे अस्पष्टता और गलतफहमी पैदा हो सकती है। यदि मैं अन्य ट्रेड-ऑफ पसंद करता हूं, तो मैं एक 3-पार्टी लाइब्रेरी चुन सकता हूं या इसे स्वयं लिख सकता हूं।
मार्शमैल

13
@marshallm जो सुनने में वाकई शानदार है! मुझे डर है कि रस्ट को कई नए लोगों ने उन फैसलों को गलत समझा जो रस्ट डिजाइनरों ने किए हैं और बस उन्हें बिना किसी लाभ के लिए बहुत जटिल होने के रूप में लिखना है। यहां सवाल पूछने और जवाब देने से, मुझे इस देखभाल के लिए सराहना मिली है कि इस तरह के डिजाइनों में जाने की जरूरत है और उम्मीद है कि यह एक बेहतर प्रोग्रामर बन जाए। खुले दिमाग रखना और अधिक सीखने के लिए तैयार रहना एक प्रोग्रामर के रूप में एक महान विशेषता है।
शीपस्टर

6
"तुर्की मैं" लोकेल निर्भरता है कि और अधिक प्रासंगिक छँटाई की तुलना में इस खास सवाल करने के लिए है का एक उदाहरण है।
ह्यून

6
मुझे आश्चर्य है कि उनके पास to_uppercase और to_lowercase है, लेकिन to_titlecase नहीं। IIRC, कुछ यूनिकोड वर्णों का वास्तव में एक विशेष शीर्षक संस्करण है।
टिम

6
वैसे, एक भी कोड बिंदु कन्वर्ट करने के लिए सही इकाई नहीं हो सकता है। क्या होगा यदि पहला चरित्र एक अंगूर समूह है जिसे ऊपरी आवरण के समय विशेष हैंडलिंग प्राप्त करनी चाहिए? (ऐसा होता है कि विघटित umlauts काम करते हैं यदि आप केवल ऊपरी-आधार आधार चरित्र करते हैं, लेकिन मुझे नहीं पता कि क्या यह सार्वभौमिक रूप से सच है।)
सेबस्टियन रेडल

23

क्या इससे आसान तरीका है, और यदि हां, तो क्या है? यदि नहीं, तो रस्ट को इस तरह से क्यों बनाया गया है?

खैर, हाँ और नहीं। आपका कोड है, जैसा कि अन्य उत्तर में बताया गया है, सही नहीं है, और अगर आप इसे བོད་ ལ་, की तरह कुछ देते हैं तो घबराएंगे। इसलिए रुस्त के मानक पुस्तकालय के साथ ऐसा करना आपके द्वारा शुरू किए गए विचार से भी कठिन है।

हालांकि, रस्ट को कोड के पुन: उपयोग को प्रोत्साहित करने और पुस्तकालयों में लाना आसान बनाने के लिए डिज़ाइन किया गया है। तो एक स्ट्रिंग को कैपिटलाइज़ करने का मुहावरेदार तरीका वास्तव में काफी प्रभावोत्पादक है:

extern crate inflector;
use inflector::Inflector;

let capitalized = "some string".to_title_case();

4
उपयोगकर्ता का प्रश्न अधिक लगता है जैसे वह चाहेगा .to_sentence_case()
क्रिस्टोफर Oezbek

1
अफसोस की बात है कि यह चीजों को नाम देने में मदद नहीं करता है ... यह बहुत बढ़िया पुस्तकालय है और मैंने इसे पहले कभी नहीं देखा था, लेकिन यह याद रखना मुश्किल है (मेरे लिए) और ऐसे कार्यों के लिए है, जो वास्तविक विभक्ति के साथ शायद ही कुछ करना है। आपका उदाहरण है।
सहसहाय २ '’१

11

यह विशेष रूप से जटिल नहीं है यदि आप अपने इनपुट को ASCII- केवल स्ट्रिंग्स तक सीमित करने में सक्षम हैं।

चूंकि रुस्ट 1.23, strमें एक make_ascii_uppercaseविधि है (पुराने रस्ट संस्करणों में, यह AsciiExtविशेषता के माध्यम से उपलब्ध था )। इसका मतलब है कि आप ASCII- केवल स्ट्रिंग स्लाइस को बड़े आसानी से जोड़ सकते हैं:

fn make_ascii_titlecase(s: &mut str) {
    if let Some(r) = s.get_mut(0..1) {
        r.make_ascii_uppercase();
    }
}

यह हो जाएगा "taylor"में "Taylor"है, लेकिन यह चालू नहीं होगा "édouard"में "Édouard"। ( खेल का मैदान )

सावधानी से प्रयोग करें।


2
एक नौसिखिया बाहर मदद करो, क्यों rम्यूट है? मैं देख रहा हूँ कि sएक उत्परिवर्ती है str। ओह्ह्ह ठीक है: मेरे पास अपने स्वयं के प्रश्न का उत्तर है: get_mut(यहां w / a श्रेणी कहा जाता है) स्पष्ट रूप से रिटर्न करता है Option<&mut>
स्टीवन लू

0

इस तरह से मैंने इस समस्या को हल किया, ध्यान दें कि मुझे यह जांचना था कि क्या अपरकेस में बदलने से पहले सेल्फी नहीं है।

trait TitleCase {
    fn title(&self) -> String;
}

impl TitleCase for &str {
    fn title(&self) -> String {
        if !self.is_ascii() || self.is_empty() {
            return String::from(*self);
        }
        let (head, tail) = self.split_at(1);
        head.to_uppercase() + tail
    }
}

pub fn main() {
    println!("{}", "bruno".title());
    println!("{}", "b".title());
    println!("{}", "🦀".title());
    println!("{}", "ß".title());
    println!("{}", "".title());
    println!("{}", "བོད་སྐད་ལ".title());
}

उत्पादन

Bruno
B
🦀
ß

བོད་སྐད་ལ 

-1

यहाँ एक संस्करण है जो @ Shepmaster के बेहतर संस्करण की तुलना में थोड़ा धीमा है, लेकिन अधिक मुहावरेदार भी है :

fn capitalize_first(s: &str) -> String {
    let mut chars = s.chars();
    chars
        .next()
        .map(|first_letter| first_letter.to_uppercase())
        .into_iter()
        .flatten()
        .chain(chars)
        .collect()
}

-1

मैंने इसे इस तरह किया:

fn str_cap(s: &str) -> String {
  format!("{}{}", (&s[..1].to_string()).to_uppercase(), &s[1..])
}

यदि यह ASCII स्ट्रिंग नहीं है:

fn str_cap(s: &str) -> String {
  format!("{}{}", s.chars().next().unwrap().to_uppercase(), 
  s.chars().skip(1).collect::<String>())
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.