मैं जावा स्ट्रिंग के यूनिकोड कोडपॉइंट्स के माध्यम से पुनरावृति कैसे कर सकता हूं?


105

इसलिए मैं इसके बारे में जानता हूं String#codePointAt(int), लेकिन यह charऑफसेट द्वारा अनुक्रमित है , कोडपॉइंट ऑफसेट द्वारा नहीं।

मैं कुछ करने की कोशिश कर रहा हूँ जैसे:

  • एक सूचकांक में String#charAt(int)पाने के लिए उपयोग करनाchar
  • परीक्षण है कि क्या charमें है उच्च surrogates रेंज
    • यदि हां, तो String#codePointAt(int)कोडपॉइंट प्राप्त करने के लिए उपयोग करें, और सूचकांक को 2 से बढ़ाएँ
    • यदि नहीं, तो दिए गए charमान का उपयोग कोडपॉइंट के रूप में करें, और इंडेक्स को 1 से बढ़ाएँ

लेकिन मेरी चिंताएं हैं

  • मुझे यकीन नहीं है कि कोडपॉइंट जो स्वाभाविक रूप से उच्च-सरोगेट रेंज में हैं, उन्हें दो charमानों या एक के रूप में संग्रहीत किया जाएगा
  • यह पात्रों के माध्यम से पुनरावृति करने के लिए एक भयानक महंगा तरीका लगता है
  • किसी को कुछ बेहतर के साथ आया होगा।

जवाबों:


143

हाँ, जावा स्ट्रिंग्स के आंतरिक अभ्यावेदन के लिए UTF-16-esque एन्कोडिंग का उपयोग करता है, और, हाँ, यह सरोगेसी योजना का उपयोग करके बेसिक मल्टीलिंगुअल प्लेन ( BMP ) के बाहर वर्णों को एनकोड करता है ।

यदि आप जानते हैं कि आप बीएमपी के बाहर के पात्रों के साथ काम कर रहे हैं, तो यहां जावा स्ट्रिंग के पात्रों पर पुनरावृति करने के लिए विहित तरीका है:

final int length = s.length();
for (int offset = 0; offset < length; ) {
   final int codepoint = s.codePointAt(offset);

   // do something with the codepoint

   offset += Character.charCount(codepoint);
}

2
के रूप में के लिए है या नहीं यह "महंगा" है, अच्छी तरह से ... कोई अन्य जावा में बनाया रास्ता है। लेकिन अगर आप केवल लैटिन / यूरोपीय / सिरिलिक / ग्रीक / हिब्रू / अरबी लिपियों के साथ काम कर रहे हैं, तो आप बस अपने दिल की सामग्री के लिए s.charAt ()। :)
जोनाथन फीनबर्ग

24
लेकिन आपको नहीं करना चाहिए। उदाहरण के लिए यदि आपका प्रोग्राम XML को आउटपुट करता है और यदि कोई इसे कुछ अस्पष्ट गणितीय ऑपरेटर देता है, तो अचानक आपका XML अमान्य हो सकता है।
मेकैनिकल घोंघा

2
मैंने इस्तेमाल किया होता offset = s.offsetByCodePoints(offset, 1);। क्या offset += Character.charCount(codepoint);इसके बजाय उपयोग करने में कुछ लाभ है ?
पॉल ग्रोके

3
@ मेकेनिकल मुझे आपकी टिप्पणी समझ नहीं आ रही है। एक्सएमएल के आउटपुट के कारण यह जवाब गलत क्यों होगा?
गिली

3
@ जवाब ठीक है। वह @Jonathan Feinberg की टिप्पणी का उल्लेख कर रहे थे जिसमें वह charAt()एक बुरे विचार का उपयोग करने की वकालत करता है
RecursiveExceptionException

72

जावा 8 को जोड़ा गया है CharSequence#codePointsजिसमें IntStreamकोड पॉइंट्स हैं। आप सीधे उन पर पुनरावृति करने के लिए धारा का उपयोग कर सकते हैं:

string.codePoints().forEach(c -> ...);

या एक सरणी में स्ट्रीम एकत्र करके लूप के लिए:

for(int c : string.codePoints().toArray()){
    ...
}

ये तरीके संभवतः जोनाथन फ़िनबर्ग के समाधान से अधिक महंगे हैं , लेकिन वे पढ़ने / लिखने के लिए तेज़ हैं और प्रदर्शन अंतर आमतौर पर महत्वहीन होगा।


3
for (int c : (Iterable<Integer>) () -> string.codePoints().iterator())भी काम करता है।
साक १०२

2
@ Saka1029: s कोड का थोड़ा छोटा संस्करण:for (int c : (Iterable<Integer>) string.codePoints()::iterator) ...
Lii

7

कोड बिंदुओं पर Iterating सूर्य पर एक सुविधा अनुरोध के रूप में दर्ज किया गया है।

सन बग एंट्री देखें

वहाँ भी एक उदाहरण है कि स्ट्रिंग कोडपॉइंट्स पर पुनरावृति कैसे करें।


6
Java 8 में अब एक कोडपॉइंट () स्टिंग में बनाया गया तरीका है: docs.oracle.com/javase/8/docs/api/java/lang/…
Dov Wasserman

7

मैंने सोचा कि मैं एक वर्कअराउंड विधि जोड़ूंगा जो कि फॉर्च लूप्स ( रेफ ) के साथ काम करती है , साथ ही आप इसे जावा 8 की नई स्ट्रिंग # कोडपॉइंट विधि में आसानी से बदल सकते हैं जब आप जावा 8 पर जाते हैं:

आप इसे इस तरह से foreach के साथ उपयोग कर सकते हैं:

 for(int codePoint : codePoints(myString)) {
   ....
 }

यहाँ सहायक सहायक है:

public static Iterable<Integer> codePoints(final String string) {
  return new Iterable<Integer>() {
    public Iterator<Integer> iterator() {
      return new Iterator<Integer>() {
        int nextIndex = 0;
        public boolean hasNext() {
          return nextIndex < string.length();
        }
        public Integer next() {
          int result = string.codePointAt(nextIndex);
          nextIndex += Character.charCount(result);
          return result;
        }
        public void remove() {
          throw new UnsupportedOperationException();
        }
      };
    }
  };
}

या वैकल्पिक रूप से यदि आप किसी स्ट्रिंग को इंट के सरणी में बदलना चाहते हैं (जो उपरोक्त दृष्टिकोण से अधिक रैम का उपयोग कर सकता है):

 public static List<Integer> stringToCodePoints(String in) {
    if( in == null)
      throw new NullPointerException("got null");
    List<Integer> out = new ArrayList<Integer>();
    final int length = in.length();
    for (int offset = 0; offset < length; ) {
      final int codepoint = in.codePointAt(offset);
      out.add(codepoint);
      offset += Character.charCount(codepoint);
    }
    return out;
  }

शुक्र है कि "कोडपॉइंट्स" का उपयोग सुरक्षित रूप से UTF-16 (जावा के आंतरिक स्ट्रिंग प्रतिनिधित्व) के सरोगेट जोड़ी-नेस को संभालता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.