2017-08-24 2 views
5

मैं स्विफ्ट 4 में एक तरीका ढूंढ रहा हूं, यह जांचने के लिए कि कोई कैरेक्टर मनमाने ढंग से कैरेक्टरसेट का सदस्य है या नहीं। मेरे पास यह Scanner वर्ग है जिसका उपयोग कुछ हल्के पार्सिंग के लिए किया जाएगा। कक्षा में कार्यों में से एक मौजूदा वर्ण पर, किसी भी वर्ण को छोड़ना है, जो संभव वर्णों के एक निश्चित सेट से संबंधित है।क्या कैरेक्टरसेट में स्विफ्ट 4 में कैरेक्टर है या नहीं, यह जांचने का सबसे अच्छा तरीका क्या है?

class MyScanner { 
    let str: String 
    var idx: String.Index 
    init(_ string: String) { 
    str = string 
    idx = str.startIndex 
    } 
    var remains: String { return String(str[idx..<str.endIndex])} 

    func skip(charactersIn characters: CharacterSet) { 
    while idx < str.endIndex && characters.contains(str[idx])) { 
     idx = source.index(idx, offsetBy: 1) 
    } 
    } 
} 

let scanner = MyScanner("fizz buzz fizz") 
scanner.skip(charactersIn: CharacterSet.alphanumerics) 
scanner.skip(charactersIn: CharacterSet.whitespaces) 
print("what remains: \"\(scanner.remains)\"") 

मैं skip(charactersIn:) समारोह को लागू करने के लिए इतना है कि इसके बाद के संस्करण कोड buzz fizz मुद्रित होगा चाहते हैं।

मुश्किल हिस्सा while में characters.contains(str[idx])) है - .contains() एक Unicode.Scalar आवश्यकता है, और मैं एक नुकसान अगले कदम पता लगाने की कोशिश में हूँ।

मैं मैं skip कार्य करने के लिए एक String पास कर सकता है पता है, लेकिन मैं क्योंकि सभी सुविधाजनक स्थिर सदस्यों (alphanumerics, whitespaces, आदि) की, यह एक CharacterSet के साथ काम करने के लिए एक रास्ता खोजने के लिए चाहते हैं।

का परीक्षण कैसे करता है यदि इसमें Character है?

+0

'एनएसएसकेनर' नामक एक सिस्टम क्लास है, जिसे स्विफ्ट में 'स्कैनर' के रूप में ब्रिज किया गया है। क्या आपने इसे चेक आउट किया है? –

+0

एनएसएसकेनर निश्चित रूप से एक पहिया की तरह दिखता है जिसे मैं पहले ब्लश पर पुनः आविष्कार कर रहा हूं। एनएस अर्थशास्त्र के बारे में पागल नहीं है (एक'out 'NSString?' Param का उपयोग करता है), लेकिन यह चाल हो सकता है। जिज्ञासा से, मैंने [स्रोत] (https://github.com/apple/swift-corelibs-foundation/blob/master/Foundation/Scanner.swift) को देखा, और यह 'स्ट्रिंग' को' ऐरे में परिवर्तित करता है ', और यह 'स्किप' फ़ंक्शन है तो बस 'set.contains (यूनिकोडस्कालर (वर्तमान कैरेक्टर)!) का उपयोग करता है। – PocketLogic

+0

यदि आपको 'एनएसएसकेनर' के एनएस अर्थशास्त्र पसंद नहीं हैं, तो फाउंडेशन के 'स्कैनर' का उपयोग करें, जो एनएस प्रकारों का उपयोग नहीं करता है। निश्चित रूप से मौजूदा वर्ग के नाम से अपनी कक्षा को परिभाषित न करें। यह सिर्फ उलझन में जा रहा है। – Rob

उत्तर

3

मुझे पता है कि आप उपयोग करना चाहता था कर रहे हैं कर सकते हैं CharacterSetString के बजाय, लेकिन CharacterSet एक से अधिक Unicode.Scalar से बना वर्णों का समर्थन नहीं करता है (अभी तक, कम से कम)। डब्ल्यूडब्ल्यूडीसी 2017 वीडियो What's New in Swift में स्ट्रिंग चर्चा में ऐप्पल ने "पारिवारिक" चरित्र() या अंतर्राष्ट्रीय ध्वज वर्ण (उदा। "" या "") देखें। कई त्वचा टोन इमोजी भी इस व्यवहार को प्रकट करते हैं (उदा। बनाम)।

परिणामस्वरूप, मैं CharacterSet का उपयोग करने से सावधान रहूंगा (जो "खोज परिचालनों में उपयोग के लिए यूनिकोड वर्ण मानों का सेट" है)। या, यदि आप सुविधा के लिए इस विधि को प्रदान करना चाहते हैं, तो ध्यान रखें कि यह एकाधिक यूनिकोड स्केलर्स द्वारा वर्णित वर्णों के साथ सही ढंग से काम नहीं करेगा।

तो, आप एक स्कैनर कि दोनों CharacterSet और Stringskip विधि के renditions प्रदान करता है पेश कर सकती है:

class MyScanner { 
    let string: String 
    var index: String.Index 

    init(_ string: String) { 
     self.string = string 
     index = string.startIndex 
    } 

    var remains: String { return String(string[index...]) } 

    /// Skip characters in a string 
    /// 
    /// This rendition is safe to use with strings that have characters 
    /// represented by more than one unicode scalar. 
    /// 
    /// - Parameter skipString: A string with all of the characters to skip. 

    func skip(charactersIn skipString: String) { 
     while index < string.endIndex, skipString.contains(string[index]) { 
      index = string.index(index, offsetBy: 1) 
     } 
    } 

    /// Skip characters in character set 
    /// 
    /// Note, character sets cannot (yet) include characters that are represented by 
    /// more than one unicode scalar (e.g. ‍‍‍ or or). If you want to test 
    /// for these multi-unicode characters, you have to use the `String` rendition of 
    /// this method. 
    /// 
    /// This will simply stop scanning if it encounters a multi-unicode character in 
    /// the string being scanned (because it knows the `CharacterSet` can only represent 
    /// single-unicode characters) and you want to avoid false positives (e.g., mistaking 
    /// the Jamaican flag, , for the Japanese flag,). 
    /// 
    /// - Parameter characterSet: The character set to check for membership. 

    func skip(charactersIn characterSet: CharacterSet) { 
     while index < string.endIndex, 
      string[index].unicodeScalars.count == 1, 
      let character = string[index].unicodeScalars.first, 
      characterSet.contains(character) { 
       index = string.index(index, offsetBy: 1) 
     } 
    } 

} 

इस प्रकार, आपके सरल उदाहरण अभी भी काम करेगा:

let scanner = MyScanner("fizz buzz fizz") 
scanner.skip(charactersIn: CharacterSet.alphanumerics) 
scanner.skip(charactersIn: CharacterSet.whitespaces) 
print(scanner.remains) // "buzz fizz" 

लेकिन String का उपयोग प्रतिपादन यदि आप जिन अक्षरों को छोड़ना चाहते हैं उनमें एकाधिक यूनिकोड स्केलर शामिल हो सकते हैं:

let family = "\u{200D}\u{200D}\u{200D}" // ‍‍‍ 
let boy = "" 

let charactersToSkip = family + boy 

let string = boy + family + "foobar" // ‍‍‍foobar 

let scanner = MyScanner(string) 
scanner.skip(charactersIn: charactersToSkip) 
print(scanner.remains)    // foobar 

माइकल झरना के रूप में नीचे टिप्पणी में बताया गया है, CharacterSet एक बग है और यहां तक ​​कि सही ढंग से 32-बिट Unicode.Scalar मानों का प्रबंधन नहीं है, जिसका अर्थ है कि यह और भी एकल अदिश वर्ण ठीक से संभाल नहीं करता है तो मूल्य 0xffff से अधिक है (इमोजी सहित, दूसरों के बीच)। String प्रतिपादन, उपरोक्त, इन सही ढंग से संभालता है, यद्यपि।

+2

दिलचस्प बात यह है कि' कैरेक्टरसेट 'इमोजी को भी संभाल नहीं देता है जो एक यूनिकोड के साथ प्रदर्शित होता है स्केलर (= 128518) हालांकि यह 'झूठा' लौटाता है: 'कैरेक्टरसेट (वर्ण: "एबीसी")। (यूनिकोडस्कालर (128518)!) ' –

+0

हाँ, चरित्र सेट के एकल स्केलर सीमा से ऊपर और परे, जाहिर है कि एक बग है 'कैरेक्टरसेट' के 32-बिट स्केलरों के हैंडलिंग में, उन्हें 16-बिट स्केलर की तरह संभालना। जैसे 'यूनिकोड.Scalar (62982) '(यानी' 128518 &&xxff') के लिए अपनी स्ट्रिंग में देखने का प्रयास करें; जबरदस्त हंसी। यह सभी 16-बिट स्केलर के साथ ठीक और बेवकूफ काम करता है, लेकिन जब आप 'UInt16.max' से अधिक मानों के साथ 32-बिट स्केलर का उपयोग करने का प्रयास करते हैं तो यह एक ट्रेन मलबे है। हमें एक बग रिपोर्ट दर्ज करनी चाहिए। मुझे ऐसा करने में खुशी है, जब तक कि आप इसे नहीं करेंगे। – Rob

1

सुनिश्चित नहीं हैं कि अगर यह सबसे कारगर तरीका है, लेकिन आप एक नया CharSet बना सकते हैं और देखें कि क्या उन्होंने उप/सुपर सेट (सेट तुलना नहीं बल्कि जल्दी है)

let newSet = CharacterSet(charactersIn: "a") 
// let newSet = CharacterSet(charactersIn: "\(character)") 
print(newSet.isSubset(of: CharacterSet.decimalDigits)) // false 
print(newSet.isSubset(of: CharacterSet.alphanumerics)) // true 
संबंधित मुद्दे

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