Путаница в окончаниях строк - PullRequest
0 голосов
/ 02 января 2012

Я сделал простой парсер с Java, который читает файл по одному символу за раз и создает слова.

Я попытался запустить его под Linux и заметил, что поиск '\n' не работает. Хотя, если я сравниваю символ со значением 10, он работает как положено. Согласно таблице ASCII значение 10 является LF (перевод строки). Я где-то читал (я не помню, где), что Java должна быть в состоянии найти новую строку только путем поиска '\n'.

Я использую BufferedReader и метод read для чтения символов.

EDIT

readLine нельзя использовать, потому что это создаст другие проблемы

Похоже, проблема возникает, когда я использую файлы с окончаниями файлов Mac / Windows в Linux.

Ответы [ 3 ]

2 голосов
/ 02 января 2012

Используйте readLine() для чтения текста построчно

Пример

FileInputStream fstream = new FileInputStream("textfile.txt");
  // Get the object of DataInputStream
  DataInputStream in = new DataInputStream(fstream);
  BufferedReader br = new BufferedReader(new InputStreamReader(in));
  String strLine;
  //Read File Line By Line
  while ((strLine = br.readLine()) != null)   {
  // Print the content on the console
  System.out.println (strLine);
  }
  //Close the input stream
  in.close();
    }catch (Exception e){//Catch exception if any
  System.err.println("Error: " + e.getMessage());
  }
1 голос
/ 02 января 2012

вот два способа сделать это

1 - используйте чтение построчно и разделяйте каждое из них с помощью регулярного выражения, чтобы получить отдельные слова

2 - напишите свой собственный метод isDelimiter и используйте его, чтобы проверить, достиг ли вы расщепления или нет

package misctests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;


public class SplitToWords {

    String someWords = "Lorem ipsum\r\n(dolor@sit)amet,\nconsetetur!\rsadipscing'elitr;sed~diam";
    String delimsRegEx = "[\\s;,\\(\\)!'@~]+";
    String delimsPlain = ";,()!'@~"; // without whitespaces

    String[] expectedWords = {
        "Lorem",
        "ipsum",
        "dolor",
        "sit",
        "amet",
        "consetetur",
        "sadipscing",
        "elitr",
        "sed",
        "diam"
    };

    private static final class StringReader {
        String input = null;
        int pos = 0;
        int len = 0;
        StringReader(String input) {
            this.input = input == null ? "" : input;
            len = this.input.length();
        }

        public boolean hasMoreChars() {
            return pos < len;
        }

        public int read() {
            return hasMoreChars() ? ((int) input.charAt(pos++)) : 0;
        }
    }

    @Test
    public void splitToWords_1() {
        String[] actual = someWords.split(delimsRegEx);
        assertEqualsWords(expectedWords, actual);
    }

    @Test
    public void splitToWords_2() {
        StringReader sr = new StringReader(someWords);
        List<String> words = new ArrayList<String>();
        StringBuilder sb = null;
        int c = 0;
        while(sr.hasMoreChars()) {
            c = sr.read();
            while(sr.hasMoreChars() && isDelimiter(c)) {
                c = sr.read();
            }
            sb = new StringBuilder();
            while(sr.hasMoreChars() && ! isDelimiter(c)) {
                sb.append((char)c);
                c = sr.read();
            }
            if(! isDelimiter(c)) {
                sb.append((char)c);
            }
            words.add(sb.toString());
        }

        String[] actual = new String[words.size()];
        words.toArray(actual);

        assertEqualsWords(expectedWords, actual);
    }

    private boolean isDelimiter(int c) {
        return (Character.isWhitespace(c) ||
            delimsPlain.contains(new String(""+(char)c))); // this part is subject for optimization
    }

    private void assertEqualsWords(String[] expected, String[] actual) {
        assertNotNull(expected);
        assertNotNull(actual);
        assertEquals(expected.length, actual.length);
        for(int i = 0; i < expected.length; i++) {
            assertEquals(expected[i], actual[i]);
        }
    }
}
1 голос
/ 02 января 2012

Если вы читаете файлы побайтно, вы должны позаботиться обо всех трех случаях '\ n' для Linux, "\ r \ n" для Windows и "\ r" для Mac.

Вместо этого используйте метод readLine.Он заботится об этих вещах для вас и возвращает только строку без каких-либо ограничителей.После прочтения каждой строки вы можете разбить ее на токены, чтобы получить отдельные слова.

Также рассмотрите возможность использования системного свойства "line.separator".Он всегда содержит системно-зависимый терминатор строки, который, по крайней мере, делает ваш код (не созданные файлы) более переносимым.

...