1

我在java中调用grep来分别计算语料库中单词列表的数量。

BufferedReader fb = new BufferedReader(
 new InputStreamReader(   
  new FileInputStream("french.txt"), "UTF8"));

while ((l = fb.readLine()) != null){
String lpt = "\\b"+l+"\\b";
String[] args = new String[]{"grep","-ic",lpt,corpus};
Process grepCommand = Runtime.getRuntime().exec(args);
grep.waitFor()
}
BufferedReader grepInput = new BufferedReader(new InputStreamReader(grep.getInputStream()));
int tmp = Integer.parseInt(grepInput.readLine());
System.out.println(l+"\t"+tmp);

这适用于我的英语单词列表和语料库。但我也有一个法语单词表和语料库。它不适用于法语,java 控制台上的示例输出如下所示:

� bord      0
� c�t�      0

正确形式:“à bord”和“à côté”。

现在我的问题是:问题出在哪里?我应该修复我的 java 代码,还是 grep 问题?如果是这样,我该如何解决。(即使我将编码更改为 UTF-8,我也无法在终端上正确看到法语字符)。

4

2 回答 2

2

问题出在您的设计中。不要从 java 调用 grep。改用纯 java 实现:逐行读取文件并使用纯 java API 实现您自己的“grep”。

但说真的,我相信问题出在你的外壳上。您是否尝试手动运行 grep 并过滤法语字符?我相信它对你不起作用。它取决于您的 shell 配置,因此取决于平台。Java 可以提供独立于平台的解决方案。为了实现这一点,您应该尽可能避免使用非纯 java 技术,包括执行命令行实用程序。

顺便说一句,逐行读取文件并使用String.contains()或模式匹配进行行过滤的代码甚至比运行的代码更短grep

于 2013-04-07T11:43:04.270 回答
0

我建议您逐行阅读文件,然后split在单词边界上调用以获取单词数。

public static void main(String[] args) throws IOException {
    final File file = new File("myFile");
    try (final BufferedReader bufferedReader =
            new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            final String[] words = line.split("\\b");
            System.out.println(words.length + " words in line \"" + line + "\".");
        }
    }
}

这样可以避免从您的程序中调用 grep。

您得到的奇怪字符很可能与使用错误的编码有关。你确定你的文件是“UTF-8”吗?

编辑

OP 希望逐行读取一个文件,然后在另一个文件中搜索读取行的出现。

这仍然可以使用 java 更轻松地完成。根据您的其他文件有多大,您可以先将其读入内存并进行搜索,也可以逐行搜索

将文件读入内存的简单示例:

public static void main(String[] args) throws UnsupportedEncodingException, IOException {
    final File corpusFile = new File("corpus");
    final String corpusFileContent = readFileToString(corpusFile);
    final File file = new File("myEngramFile");
    try (final BufferedReader bufferedReader =
            new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) {
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            final int matches = countOccurencesOf(line, corpusFileContent);
        };
    }
}

private static String readFileToString(final File file) throws IOException {
    final StringBuilder stringBuilder = new StringBuilder();
    try (final FileChannel fc = new RandomAccessFile(file, "r").getChannel()) {
        final ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
        final CharsetDecoder charsetDecoder = Charset.forName("UTF-8").newDecoder();
        while (fc.read(byteBuffer) > 0) {
            byteBuffer.flip();
            stringBuilder.append(charsetDecoder.decode(byteBuffer));
            byteBuffer.reset();
        }
    }
    return stringBuilder.toString();
}

private static int countOccurencesOf(final String countMatchesOf, final String inString) {
    final Matcher matcher = Pattern.compile("\\b" + countMatchesOf + "\\b").matcher(inString);
    int count = 0;
    while (matcher.find()) {
        ++count;
    }
    return count;
}

如果您的“语料库”文件小于一百兆字节左右,这应该可以正常工作。任何更大的,你会想要改变“countOccurencesOf”方法像这样

private static int countOccurencesOf(final String countMatchesOf, final File inFile) throws IOException {
    final Pattern pattern = Pattern.compile("\\b" + countMatchesOf + "\\b");
    int count = 0;
    try (final BufferedReader bufferedReader =
            new BufferedReader(new InputStreamReader(new FileInputStream(inFile), "UTF-8"))) {
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            final Matcher matcher = pattern.matcher(line);
            while (matcher.find()) {
                ++count;
            }
        };
    }
    return count;
}

现在您只需将“文件”对象传递给方法而不是字符串化文件。

请注意,流式传输方法逐行读取文件并因此删除换行符,String如果您Pattern依赖它们存在,则需要在解析之前将它们添加回来。

于 2013-04-07T16:41:39.380 回答