3

我想在文本文件中查找“$$$$”模式的实例数。以下方法适用于某些文件,但不适用于所有文件。例如,它不适用于以下文件(http://www.hmdb.ca/downloads/structures.zip - 它是一个带有 .sdf 扩展名的压缩文本文件)我不知道为什么?我也试图逃避空格。没运气。当“$$$$”模式超过 35000 个时,它返回 11。请注意,速度至关重要。因此,我不能使用任何较慢的方法。

public static void countMoleculesInSDF(String fileName)
{
    int tot = 0;
    Scanner scan = null;
    Pattern pat = Pattern.compile("\\$\\$\\$\\$");

    try {  
        File file = new File(fileName);
        scan = new Scanner(file);
        long start = System.nanoTime();
        while (scan.findWithinHorizon(pat, 0) != null) {
            tot++;
        }
        long dur = (System.nanoTime() - start) / 1000000;
        System.out.println("Results found: " + tot + " in " + dur + " msecs");
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        scan.close();
}
}
4

2 回答 2

3

对于链接的文件和您发布的代码,我一直有218匹配的总数。这当然是不正确的:使用 notepad++ 的计数功能进行验证,文件应该包含41498匹配项。因此,Scanner(我认为)肯定有问题,并在最后一场比赛完成时开始在其中调试,即当扫描仪告诉没有更多匹配时。这样做我在它的私有方法中遇到了一个异常,它readInput()不是直接抛出而是保存在语言环境变量中。

try {
    n = source.read(buf);
} catch (IOException ioe) {
    lastException = ioe;
    n = -1;
}

可以使用以下方法检索此异常Scanner#ioException()

IOException ioException = scanner.ioException();
if (ioException != null) {
    ioException.printStackTrace();
}

然后打印此异常表明某些输入无法解码

java.nio.charset.UnmappableCharacterException: Input length = 1
    at java.nio.charset.CoderResult.throwException(CoderResult.java:278)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:338)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
    at java.io.Reader.read(Reader.java:100)
    at java.util.Scanner.readInput(Scanner.java:849)

所以我只是尝试将一个字符集传递给扫描仪的构造函数:

scan = new Scanner(file, "utf-8");

它使它起作用了!

Results found: 41498 in 2431 msecs

所以问题是扫描仪使用了平台的字符集,它不适合完全解码你拥有的文件。

故事的道德启示:

  1. 处理文本时始终显式传递字符集。
  2. 使用. IOException_Scanner

PS:一些方便的方法来引用字符串以用作正则表达式

Pattern pat = Pattern.compile("\\Q$$$$\\E");

或者

Pattern pat = Pattern.compile(Pattern.quote("$$$$"));
于 2013-10-08T19:31:13.483 回答
0

这就是我最终做的事情......(在你发布答案之前)。这种方法似乎比扫描仪更快。你会建议什么实施?扫描仪还是内存映射?大文件的内存映射会失败吗?没有把握..

private static final Charset CHARSET = Charset.forName("ISO-8859-15");
private static final CharsetDecoder DECODER = CHARSET.newDecoder();

public static int getNoOfMoleculesInSDF(String fileName) 
    {   
    int total=0;
    try
    {    
    Pattern endOfMoleculePattern = Pattern.compile("\\$\\$\\$\\$");
    FileInputStream fis = new FileInputStream(fileName);
    FileChannel fc = fis.getChannel();
    int fileSize = (int) fc.size();
    MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
    CharBuffer cb = DECODER.decode(mbb);
    Matcher matcher = endOfMoleculePattern.matcher(cb);
    while (matcher.find()) {
      total++;
    }
    }
    catch(Exception e)
    {
        LOGGER.error("An error occured while counting molecules in the SD file");
    }
    return total;
    }
于 2013-10-08T21:02:24.293 回答