2014-10-13 13 views
5

मैं "input.txt" से तार पढ़ सकते हैं और छोड़ना चाहते हैं का उपयोग कर केवल उन जो लाइन की शुरुआत में कोई # (टिप्पणी) प्रतीक है। ,एक जंग स्ट्रिंग में एक चरित्र की तुलना अनुक्रमण

use std::io::{BufRead, BufReader}; 
use std::fs::File; 

fn main() { 
    let file = BufReader::new(File::open("input.txt").unwrap()); 
    let lines: Vec<String> = file.lines().map(|x| x.unwrap()).collect(); 
    let mut iter = lines.iter().filter(|&x| x.chars().next() != "#".chars().next()); 
    println!("{}", iter.next().unwrap()); 
} 

लेकिन इस लाइन

|&x| x.chars().next() != "#".chars().next() 

मेरे लिए बदबू आती है क्योंकि यह इस |x| x[0] == "#" की तरह लग सकता है और मैं स्ट्रिंग में दूसरा चरित्र की जाँच नहीं कर सकते हैं: मैं इस कोड लिखा था।

तो मैं इस कोड को दोबारा कैसे कर सकता हूं?

उत्तर

9

जंग तार UTF-8 एन्कोडिंग में पात्रों का प्रतिनिधित्व बाइट्स की एक दृश्य के रूप में जमा हो जाती है। यूटीएफ -8 एक चर-चौड़ाई एन्कोडिंग है, इसलिए बाइट इंडेक्सिंग आपको एक चरित्र के अंदर छोड़ सकती है, जो स्पष्ट रूप से असुरक्षित है। लेकिन इंडेक्स द्वारा कोड पॉइंट प्राप्त करना एक ओ (एन) ऑपरेशन है। इसके अलावा, इंडेक्सिंग कोड पॉइंट वह नहीं है जो आप वास्तव में करना चाहते हैं, क्योंकि ऐसे कोड पॉइंट होते हैं जिनमें डायरेक्ट्री या अन्य संशोधक जैसे वर्ण भी नहीं होते हैं। इंडेक्सिंग ग्रैफेम क्लस्टर सही दृष्टिकोण के करीब हैं, लेकिन आमतौर पर पाठ प्रतिपादन या संभवतः भाषा प्रसंस्करण में आवश्यक होता है।

मैं क्या मतलब है कि एक स्ट्रिंग का अनुक्रमण ठीक से परिभाषित करना कठिन है, और ज्यादातर लोगों को आम तौर पर चाहते हैं गलत है। इसलिए जंग जंग पर एक सामान्य सूचकांक ऑपरेशन प्रदान नहीं करता है।

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

सबसे पहले, आप हमेशा बाइट्स की अंतर्निहित अनुक्रम के एक दृश्य प्राप्त कर सकते हैं। &str में as_bytes() विधि है जो &[u8] लौटाती है, स्ट्रिंग के बाइट्स का एक टुकड़ा होता है।

x.as_bytes()[0] != b'#' 

नोट विशेष अंकन: तो फिर तुम हमेशा की तरह अनुक्रमण आपरेशन का उपयोग कर सकते b'#' का अर्थ है "ASCII वर्ण प्रकार u8 की #", यानी यह एक बाइट वर्ण शाब्दिक (है भी ध्यान रखें कि आप "#".chars().next() लिखने की जरूरत नहीं है चरित्र # प्राप्त करने के लिए, आप बस '#' - एक सादा चरित्र अक्षरशः लिख सकते हैं)। यह असुरक्षित है, हालांकि, &str यूटीएफ -8-एन्कोडेड स्ट्रिंग है और पहले वर्ण में एक से अधिक बाइट शामिल हो सकते हैं।

जंग में ASCII डेटा को संभालने के लिए उचित तरीके से ascii crate उपयोग करने के लिए है। आप विधि के साथ &str से &AsciiStr पर जा सकते हैं। तो फिर तुम इसे इस तरह उपयोग कर सकते हैं:

extern crate ascii; 
use ascii::{AsAsciiStr, AsciiChar}; 

// ... 

x.as_ascii_str().unwrap()[0] != AsciiChar::Hash 

इस तरह आप थोड़ा और अधिक टाइपिंग की आवश्यकता होगी, लेकिन आप, बदले में और अधिक सुरक्षा मिल जाएगा क्योंकि as_ascii_str() जांच करता है कि आप ASCII डेटा के साथ ही काम करते हैं।

कभी कभी, तथापि, तुम बस वास्तव में, वर्ण के रूप में यह व्याख्या भले ही स्रोत कुछ ASCII वर्ण हैं बिना, बाइनरी डेटा के साथ काम करना चाहते हैं। ऐसा हो सकता है, उदाहरण के लिए, जब आप मार्कडाउन जैसी कुछ मार्कअप भाषा के लिए एक पार्सर लिख रहे हों। इस मामले में आप बाइट्स की एक दृश्य के रूप में पूरे इनपुट का इलाज कर सकते हैं:।

use std::io::{Read, BufReader}; 
use std::fs::File; 

fn main() { 
    let mut file = BufReader::new(File::open("/etc/hosts").unwrap()); 
    let mut buf = Vec::new(); 
    file.read_to_end(&mut buf).unwrap(); 
    let mut iter = buf.split(|&c| c == b'\n').filter(|line| line[0] != b'#'); 
    println!("{:?}", iter.next().unwrap()); 
} 
+2

'एक्स [] as_bytes() [0] = ख '#'' नहीं * किसी भी सार्थक अर्थों में * असुरक्षित है।यह स्मृति सुरक्षा को खतरे में नहीं डालता है, इसमें अमान्य 'char' मान शामिल नहीं हैं, यह प्रकार के साथ फंकी चीजें नहीं करता है, और यह विशेष रूप से कुछ अर्थहीन करने की भी संभावना नहीं है। यूटीएफ -8 में, बहु-बाइट कोड बिंदु विशेष रूप से बाइट्स> 127 (यानी ASCII नहीं) से बने होते हैं, इसलिए मूल्य 35 के साथ बाइट खोजना U + 0023 कोड बिंदु की घटनाओं को खोजने का एक बिल्कुल सही तरीका है। लेकिन दिया गया: यह खराब शैली है, और बाइट्स को छोड़ना अन्य पाठ प्रसंस्करण कार्य के लिए एक बुरी आदत है। – delnan

+1

@ डेलनान, ठीक है, इस विशेष मामले में आप सही हैं। असुरक्षित (जिस अर्थ को आमतौर पर जंग के संदर्भ में उपयोग किया जाता है) शायद इसके लिए गलत शब्द है। हालांकि, 0 के अलावा किसी भी इंडेक्स के लिए एक ही चीज़ लिखना व्यर्थ और गलत है, और प्रश्न लेखक ने स्पष्ट रूप से दूसरे चरित्र और संभवतः अन्य लोगों की जांच के लिए कहा। –

+2

दूसरे कोड पॉइंट या ग्रैफेम क्लस्टर को आजमाने और जांचने के लिए इंडेक्स 1 का उपयोग करना गलत होगा। लेकिन बाइट इंडेक्सिंग जरूरी नहीं है। यूटीएफ -8 के गुण बाइट्स के संदर्भ में उप स्ट्रिंग खोजों जैसी चीजों को लिखने की अनुमति देते हैं। यह अक्सर व्यर्थ है, हां ('char' iterators आमतौर पर बेहतर होते हैं, और कई एल्गोरिदम पहले ही libstd द्वारा प्रदान किए जाते हैं), लेकिन संदेश को शूट न करें। – delnan

संबंधित मुद्दे