स्ट्रिंग लाइन को लाइन से पढ़ें


144

एक स्ट्रिंग को देखते हुए जो बहुत लंबा नहीं है, उसे लाइन द्वारा लाइन पढ़ने का सबसे अच्छा तरीका क्या है?

मुझे पता है तुम कर सकते हो:

BufferedReader reader = new BufferedReader(new StringReader(<string>));
reader.readLine();

एक और तरीका यह होगा कि आप eol पर सबस्ट्रिंग लें:

final String eol = System.getProperty("line.separator");
output = output.substring(output.indexOf(eol + 1));

किसी भी अन्य शायद इसे करने के सरल तरीके? मुझे उपरोक्त दृष्टिकोणों से कोई समस्या नहीं है, बस यह जानने की दिलचस्पी है कि क्या आप में से कोई भी ऐसा कुछ जानता है जो सरल और अधिक कुशल लग सकता है?


5
अच्छी तरह से आपकी आवश्यकता ने कहा "इसे लाइन द्वारा लाइन पढ़ें", जिसका अर्थ है कि आपको एक समय में मेमोरी में सभी लाइनों की आवश्यकता नहीं है, इसलिए मैं बफ़रडियर या स्कैनर दृष्टिकोण के साथ रहना चाहूँगा, जो भी आपको अधिक आरामदायक महसूस हो (पता नहीं जो अधिक कुशल है)। इस तरह आपकी मेमोरी आवश्यकताएं कम होती हैं। यह आपको भविष्य में एक फ़ाइल से संभावित रूप से डेटा पढ़ने के द्वारा बड़े तार का उपयोग करने के लिए एप्लिकेशन को "स्केल अप" करने की अनुमति देगा।
कैमिक्र

जवाबों:


133

आप splitस्ट्रिंग की विधि का भी उपयोग कर सकते हैं :

String[] lines = myString.split(System.getProperty("line.separator"));

यह आपको एक आसान सरणी में सभी पंक्तियाँ देता है।

मैं विभाजन के प्रदर्शन के बारे में नहीं जानता। यह नियमित अभिव्यक्ति का उपयोग करता है।


3
और आशा है कि लाइन विभाजक में रेगेक्स वर्ण नहीं हैं। :)
टॉम हॉल्टिन -

47
"line.separator" वैसे भी विश्वसनीय नहीं है। सिर्फ इसलिए कि कोड चल रहा है (उदाहरण के लिए) यूनिक्स, फ़ाइल को विंडोज-स्टाइल "\ r \ n" लाइन विभाजक होने से रोकने के लिए क्या है? BufferedReader.readLine () और Scanner.nextLine () हमेशा विभाजक की तीनों शैलियों के लिए जाँच करें।
एलन मूर

6
मुझे पता है कि यह टिप्पणी वास्तव में पुरानी है, लेकिन ... इस सवाल में फाइलों का जिक्र नहीं है। मान लें कि स्ट्रिंग को किसी फ़ाइल से पढ़ा नहीं गया था, यह दृष्टिकोण संभवतः सुरक्षित है।
जोल्टा

@Jolta यह मैन्युअल रूप से निर्मित स्ट्रिंग्स के लिए भी सुरक्षित नहीं है, यदि आप खिड़कियों पर हैं और 'String' का निर्माण '\ n' के साथ करते हैं और फिर line.separator पर विभाजित होते हैं, तो आपको कोई रेखा नहीं मिलती है।
मास्टरएक्सिलो

है ना? अगर मैं अपने linux बॉक्स पर स्ट्रिंग का उपयोग करके बनाता हूं line.separatorऔर कोई अन्य इसे उपयोग कर खिड़कियों पर पढ़ता है line.separator, तो यह अभी भी गुनगुना है। यह बेवकूफ चीजों को करने से अक्षम कोडर नहीं है, यह सिर्फ इतना है कि कैसे चीजें (हमेशा नहीं) काम करती हैं।
लैरी

205

भी है Scanner। आप इसका उपयोग इस तरह कर सकते हैं BufferedReader:

Scanner scanner = new Scanner(myString);
while (scanner.hasNextLine()) {
  String line = scanner.nextLine();
  // process the line
}
scanner.close();

मुझे लगता है कि यह थोड़ा साफ-सुथरा दृष्टिकोण है जो दोनों सुझाए गए हैं।


5
मुझे नहीं लगता कि यह एक निष्पक्ष तुलना है - String.split पूरे इनपुट पर निर्भर करता है जिसे मेमोरी में पढ़ा जाता है, जो हमेशा संभव नहीं होता है (जैसे बड़ी फ़ाइलों के लिए)।
एडम्सकी

3
इनपुट को मेमोरी में रहना है, यह देखते हुए कि इनपुट स्ट्रिंग है। मेमोरी ओवरहेड सरणी है। इसके अलावा, परिणामी स्ट्रिंग्स उसी बैक-एंड कैरेक्टर एरे का पुनः उपयोग करते हैं।
notnoop

यदि आप यूटीएफ -8 फ़ाइल को यूनिकोड वर्णों के साथ स्कैन करते हैं तो स्कैनर के गलत परिणाम उत्पन्न कर सकते हैं और स्कैनर में एन्कोडिंग निर्दिष्ट नहीं करते हैं। यह पंक्ति के अंत में एक अलग वर्ण की व्याख्या कर सकता है। विंडोज में यह अपने डिफ़ॉल्ट एन्कोडिंग का उपयोग करता है।
जीवित-प्रेम

43

चूँकि मैं विशेष रूप से दक्षता के कोण में रुचि रखता था, इसलिए मैंने थोड़ा परीक्षण वर्ग (नीचे) बनाया। 5,000,000 लाइनों के लिए परिणाम:

Comparing line breaking performance of different solutions
Testing 5000000 lines
Split (all): 14665 ms
Split (CR only): 3752 ms
Scanner: 10005
Reader: 2060

हमेशा की तरह, सटीक समय भिन्न हो सकता है, लेकिन अनुपात सही है लेकिन अक्सर मैंने इसे चलाया है।

निष्कर्ष: ओपी का "सरल" और "अधिक कुशल" आवश्यकताओं को एक साथ संतुष्ट नहीं किया जा सकता है, splitसमाधान (या तो अवतार में) सरल है, लेकिन Readerकार्यान्वयन दूसरों के हाथों को हरा देता है।

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * Test class for splitting a string into lines at linebreaks
 */
public class LineBreakTest {
    /** Main method: pass in desired line count as first parameter (default = 10000). */
    public static void main(String[] args) {
        int lineCount = args.length == 0 ? 10000 : Integer.parseInt(args[0]);
        System.out.println("Comparing line breaking performance of different solutions");
        System.out.printf("Testing %d lines%n", lineCount);
        String text = createText(lineCount);
        testSplitAllPlatforms(text);
        testSplitWindowsOnly(text);
        testScanner(text);
        testReader(text);
    }

    private static void testSplitAllPlatforms(String text) {
        long start = System.currentTimeMillis();
        text.split("\n\r|\r");
        System.out.printf("Split (regexp): %d%n", System.currentTimeMillis() - start);
    }

    private static void testSplitWindowsOnly(String text) {
        long start = System.currentTimeMillis();
        text.split("\n");
        System.out.printf("Split (CR only): %d%n", System.currentTimeMillis() - start);
    }

    private static void testScanner(String text) {
        long start = System.currentTimeMillis();
        List<String> result = new ArrayList<>();
        try (Scanner scanner = new Scanner(text)) {
            while (scanner.hasNextLine()) {
                result.add(scanner.nextLine());
            }
        }
        System.out.printf("Scanner: %d%n", System.currentTimeMillis() - start);
    }

    private static void testReader(String text) {
        long start = System.currentTimeMillis();
        List<String> result = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new StringReader(text))) {
            String line = reader.readLine();
            while (line != null) {
                result.add(line);
                line = reader.readLine();
            }
        } catch (IOException exc) {
            // quit
        }
        System.out.printf("Reader: %d%n", System.currentTimeMillis() - start);
    }

    private static String createText(int lineCount) {
        StringBuilder result = new StringBuilder();
        StringBuilder lineBuilder = new StringBuilder();
        for (int i = 0; i < 20; i++) {
            lineBuilder.append("word ");
        }
        String line = lineBuilder.toString();
        for (int i = 0; i < lineCount; i++) {
            result.append(line);
            result.append("\n");
        }
        return result.toString();
    }
}

4
Java8 के अनुसार, बफ़ररएडर के पास लाइनों की lines()वापसी का एक फ़ंक्शन है Stream<String>, जिसे आप एक सूची में इकट्ठा कर सकते हैं यदि आप चाहें, या स्ट्रीम को संसाधित कर सकते हैं।
स्टीव के

22

Apache Commons IOUtils का उपयोग करके आप इसे अच्छी तरह से कर सकते हैं

List<String> lines = IOUtils.readLines(new StringReader(string));

यह कुछ भी चालाक नहीं है, लेकिन यह अच्छा और कॉम्पैक्ट है। यह धाराओं को भी संभाल लेगा, और LineIteratorयदि आप चाहें तो आप भी इसे प्राप्त कर सकते हैं।


2
इस दृष्टिकोण का एक दोष यह है कि IOUtils.readlines(Reader)एक फेंकता है IOException। हालांकि यह संभवतः StringReader के साथ कभी नहीं होगा, आपको इसे पकड़ना या घोषित करना होगा।
sleske

एक मामूली टाइपो है, यह होना चाहिए: सूची लाइनें = IOUtils.readLines (नया StringReader (स्ट्रिंग));
टॉमी

17

Java 8जैसे Stream APIऔर सुविधाओं का उपयोग कर समाधानMethod references

new BufferedReader(new StringReader(myString))
        .lines().forEach(System.out::println);

या

public void someMethod(String myLongString) {

    new BufferedReader(new StringReader(myLongString))
            .lines().forEach(this::parseString);
}

private void parseString(String data) {
    //do something
}

11

जावा 11 के बाद से, एक नई विधि है String.lines:

/**
 * Returns a stream of lines extracted from this string,
 * separated by line terminators.
 * ...
 */
public Stream<String> lines() { ... }

उपयोग:

"line1\nline2\nlines3"
    .lines()
    .forEach(System.out::println);

7

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

import java.util.stream.*;
import java.io.*;
class test {
    public static void main(String... a) {
        String s = "this is a \nmultiline\rstring\r\nusing different newline styles";

        new BufferedReader(new StringReader(s)).lines().forEach(
            (line) -> System.out.println("one line of the string: " + line)
        );
    }
}

देता है

one line of the string: this is a
one line of the string: multiline
one line of the string: string
one line of the string: using different newline styles

जैसे बफेडरएडर की रीडलाइन में, स्वयं नया लाइन वर्ण शामिल नहीं है। सभी प्रकार के न्यूलाइन विभाजक समर्थित हैं (समान स्ट्रिंग में भी)।


पता भी नहीं चला! बहुत बहुत धन्यवाद ।
GOXR3PLUS

6

आप भी उपयोग कर सकते हैं:

String[] lines = someString.split("\n");

अगर वह काम नहीं करता है तो \nसाथ बदलने की कोशिश करें \r\n


3
न्यूलाइन के प्रतिनिधित्व को हार्डकोड करने से समाधान प्लेटफॉर्म पर निर्भर हो जाता है।
Thsoft

@thSoft मैं तर्क देता हूं कि इसे हार्डकॉउट न करने के बारे में कहा जा सकता है - यदि आप इसे हार्डकोड नहीं करते हैं, तो आपको एक ही इनपुट के लिए अलग-अलग प्लेटफॉर्म पर अलग-अलग परिणाम मिलेंगे (यानी प्लेटफॉर्म-डिपेंडेंट लाइन ब्रेक के बजाय एक ही लाइन ब्रेक के साथ इनपुट में)। यह वास्तव में एक हाँ / नहीं है और आपको यह सोचना होगा कि आपका इनपुट क्या होगा।
जिरि टुमस्क

हां, व्यवहार में मैंने सैकड़ों बार उत्तर देने के तरीके का उपयोग किया है और देखा है। यह एक पंक्ति है कि स्कैनर वर्ग का उपयोग करने की तुलना में अपने पाठ विखंडू है टूटने के लिए बस अधिक सीधा है। यही है, अगर आपका तार असामान्य रूप से बड़े पैमाने पर नहीं है।
ओलिन किर्कलैंड

5

या स्कैनर के साथ संयुक्त संसाधन खंड के साथ नई कोशिश का उपयोग करें:

   try (Scanner scanner = new Scanner(value)) {
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            // process the line
        }
    }

2

आप निम्नलिखित नियमित अभिव्यक्ति की कोशिश कर सकते हैं:

\r?\n

कोड:

String input = "\nab\n\n    \n\ncd\nef\n\n\n\n\n";
String[] lines = input.split("\\r?\\n", -1);
int n = 1;
for(String line : lines) {
    System.out.printf("\tLine %02d \"%s\"%n", n++, line);
}

आउटपुट:

Line 01 ""
Line 02 "ab"
Line 03 ""
Line 04 "    "
Line 05 ""
Line 06 "cd"
Line 07 "ef"
Line 08 ""
Line 09 ""
Line 10 ""
Line 11 ""
Line 12 ""

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