【问题标题】:check if a string is contained in a text file of words in java检查字符串是否包含在java中的单词文本文件中
【发布时间】:2018-01-24 08:19:15
【问题描述】:

我有一个来自 github 项目的文本文件(所有有效英文单词的集合),看起来像这样 words.txt

我的文本文件在我的项目中的resources 文件夹下。

我还有一个从 mysql 表中获取的行列表。 我要做的是检查每一行中的所有单词是否都是有效的英文单词,这就是为什么我将每一行与我的文件中包含的单词进行比较。

这是我迄今为止尝试过的:

 public static void englishCheck(List<String> rows) throws IOException {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    int lenght, occurancy = 0;
    for ( String row : rows ){

       File file = new File(classLoader.getResource("words.txt").getFile());


       lenght = 0;

       if ( !row.isEmpty()  ){
           System.out.println("the row : "+row);
           String[] tokens = row.split("\\W+");
           lenght = tokens.length;
           for (String token : tokens) {

               occurancy = 0;
               BufferedReader br = new BufferedReader(new FileReader(file));

               String line;
               while ((line = br.readLine()) != null ){


                   if ((line.trim().toLowerCase()).equals(token.trim().toLowerCase())){
                       occurancy ++ ;

                   }
                   if (occurancy == lenght ){ System.out.println(" this is english "+row);break;}

               }

           }





       }

   }
}

这仅适用于第一行,之后我的方法循环遍历仅显示它们的行并忽略比较,我想知道为什么这不适用于我的行集,如果我也可以像这样List&lt;String&gt; raws = Arrays.asList(raw1, raw2, raw3 ) 等预定义我的列表

【问题讨论】:

  • 超级坏主意:你在这里创建一个 n * m 双循环。你绝对想为你的每一个字一遍又一遍地阅读那个文件。
  • @DevRj /words.txt 中的数据格式是什么??一行一行的在同一行,给个样例
  • 提示:当你编辑你的源代码...确保正确格式化它。
  • @GhostCat 也许这是一个坏主意,也许您可​​以提供一种方法来验证该文件中是否包含一行中的每个单词,以及一种将该文件立即读入内存的方法,因为它是您的建议。谢谢

标签: java arraylist io string-comparison


【解决方案1】:

您可以读取words.txt 文件,将单词转换为小写,然后将单词放入HashSet

使用boolean contains(Object o)boolean containsAll(Collection&lt;?&gt; c); 方法比较每个单词。 时间是 O(n)

提示:不要在每个循环中读取文件。读取文件非常非常慢。

ClassLoader classLoader = ClassLoader.getSystemClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("words.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
List<String> wordList = new LinkedList<String>(); // You do not know word count, LinkedList is a better way.
String line = null;
while ((line = reader.readLine()) != null) {
  String[] words = line.toLowerCase().split("\\W+");
  wordList.addAll(Arrays.asList(words));
}
Set<String> wordSet = new HashSet<String>(wordList.size());
wordSet.addAll(wordList);


// then you can use the wordSet to check. 
// You shold convert the tokens to lower case.
String[] tokens = row.toLowerCase().split("\\W+");
wordSet.containsAll(Arrays.asList(tokens)); 

【讨论】:

  • 有用的回答只是一些编辑,比如你可以直接传递一些值,而不是Set&lt;String&gt; wordSet = new HashSet&lt;String&gt;(wordList.size()); wordSet.addAll(wordList);,你可以简单地这样做:Set&lt;String&gt; wordSet = new HashSet&lt;String&gt;(wordList);,谢谢
【解决方案2】:

您的代码不起作用的原因是occurancy 不能是 0 或 1 以外的任何值。您可以通过遵循逻辑或通过调试器看到这一点。

如果您的 words.txt 文件不是太大,并且您有足够的可用 RAM,您可以通过在开始时将 words.txt 文件读入内存来加快处理速度。此外,您只需要调用一次 toLowerCase(),而不是每次比较。但是,请注意语言环境。只要您没有任何非英语字符(例如德语 eszett 或希腊语 sigma),以下代码就应该可以工作。

public static void englishCheck(List<String> rows) throws IOException {
    final URI wordsUri;
    try {
        wordsUri = ClassLoader.getSystemResource("words.txt").toURI();
    } catch (URISyntaxException e) {
        throw new AssertionError(e); // can never happen
    }

    final Set<String> words = Files.lines(Paths.get(wordsUri))
            .map(String::toLowerCase)
            .collect(Collectors.toSet());

    for (String row: rows)
        if (!row.isEmpty()) {
            System.out.println("the row : " + row);
            String[] tokens = row.toLowerCase().split("\\W+");
            if (words.containsAll(Arrays.asList(tokens)))
                System.out.println(" this is english " + row);
        }
}

【讨论】:

    【解决方案3】:

    可以使用List#containsAll(Collection)的方法

    如果此列表包含所有元素,则返回 true 指定的集合。

    假设您同时填写了 myListFromRessourcesmyListFromRessources 列表,那么您可以这样做:

    List<String> myListFromRessources = Arrays.asList("A", "B", "C", "D");
    List<String> myListFromRessources = Arrays.asList("D", "B");
    
    boolean myInter = myListFromRessources.containsAll(myListFromSQL);
    System.out.println(myInter);
    myListFromSQL = Arrays.asList("D", "B", "Y");
    myInter = myListFromRessources.containsAll(myListFromSQL);
    System.out.println(myInter);
    

    【讨论】:

    • 您还想添加一些内容,可能会立即将该文件读入内存。
    • 不是真的,这就是我写的原因:“让我们假设你已经填写了两个列表”...我假设 OP 知道该怎么做因为他没有在代码中提到任何关于它的问题......
    • 我的文件是从github项目下载的一组英文单词,我对我的SQL表包含什么不清楚,可能包含一些无意义的单词(row = "ghsjgsdh hg.hg" ) or half English words row = "half valid English sentence hkdojgsv hdh") or a valid one row = "valid English sentence"`,我似乎无法理解你的建议如何适合我的情况
    • 我认为第二个 myListFromRessources 的意思是 myListFromSQL(在您的解释和代码中)。
    猜你喜欢
    • 1970-01-01
    • 2014-01-25
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多