2009-10-06 16 views
88

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

मैं की तरह कुछ कोशिश कर के बारे में सोच रहा हूँ:

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

द्वारा सूचकांक को बढ़ा देते लेकिन मेरी चिंताओं

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

उत्तर

116

हाँ, जावा स्ट्रिंग्स के आंतरिक अभ्यावेदन के लिए एक 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()। :) –

+18

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

+0

@ जोनाथन फीनबर्ग मैंने यही सोचा। लेकिन यहां आया कि विशेष गणितीय ई। यूटीएफ -16 99% समय काम करता है - लेकिन फिर यह वास्तव में दर्दनाक हो जाता है। विशेष रूप से जब समस्याएं लंबे समय तक छिपी रहती हैं। – Martin

5

पुनरावृत्ति कोड अंक के ऊपर एक सुविधा के रूप में दर्ज किया गया है:

आप जानते हैं कि बीएमपी के बाहर अक्षर के साथ काम करने वाले हैं तो फिर यहाँ एक जावा स्ट्रिंग के पात्रों से अधिक पुनरावृति करने के लिए विहित तरीका है सूर्य पर अनुरोध

देखें Sun Bug Entry

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

+3

जावा 8 में अब स्ट्रिंग में निर्मित कोडपॉइंट्स() विधि है: http://docs.oracle.com /javase/8/docs/api/java/lang/CharSequence.html#codePoints –

+0

इस कार्यवाही विधि के लिए मेरा उत्तर भी देखें जिसका उपयोग आप जावा <8 के दौरान अपने स्थान पर कर सकते हैं http://stackoverflow.com/a/ 21791059/32453 – rogerdpack

4

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

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(); 
     } 
     }; 
    } 
    }; 
} 

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

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

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

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; 
    } 
46

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

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

या एक सरणी में धारा इकट्ठा करके पाश के लिए एक साथ:

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

ये तरीके शायद Jonathan Feinbergs's solution से ज्यादा महंगे हैं, लेकिन वे पढ़ने/लिखने के लिए तेज़ हैं और प्रदर्शन अंतर आमतौर पर महत्वहीन होगा।

+0

'के लिए (int c: (Iterable )() -> string.codePoints()। Iterator()) 'भी काम करता है। – saka1029

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

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