Подсчет экземпляра определенного слова из исходного кода - PullRequest
1 голос
/ 23 декабря 2019

У меня есть цикл for в Java-файле, где код выглядит следующим образом (включая комментарии),

//This is a for loop 
for (int i = 0; i <= 10; i = i + 2) {
 System.out.println(i);
}

/*
When you know exactly how many times you want to loop through a block of code, use 
the for loop instead of a while loop
*/

Я пишу программу для чтения этого файла и подсчета числа "для"циклы в коде. Метод, который делает это в моей программе, выглядит следующим образом:

private static int wordCount(String file) throws IOException  {

    String word1 = "for";
    int wordCount = 0;
    Scanner sc = new Scanner(new File(file));
    while(sc.hasNext()){
        if (sc.next().equals(word1)){
            wordCount++;
        }
    }

    return wordCount; 
}

Однако, когда я запускаю этот код, он возвращает wordCount как 3, а не 1. Я полагаю, что это происходит потому, что он читает строки из комментариев. разделы. Как я могу изменить свой код таким образом (возможно, используя регулярное выражение), чтобы вернуть wordCount как 1 для этого экземпляра?

Ответы [ 2 ]

1 голос
/ 23 декабря 2019

Метод 1

Возможно,

(?m)^\\h*\\bfor\\s[\\s\\S]*?^\\h*\\}\\h*$

может быть несколько близко, чтобы найти выражение для этого.

Демонстрация RegEx 1

Выражение не выполнится, если будут вложенные циклы for.

Тест 1

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegularExpression{

    public static void main(String[] args){


        final String regex = "(?m)^\\h*\\bfor\\s+[\\s\\S]*?^\\h*\\}\\h*$";
        final String string = "for (int i = 0; i <= 10; i = i + 2) {\n"
             + " System.out.println(i);\n"
             + "}\n\n"
             + "for (int i = 0; i <= 10; i = i + 2) {\n"
             + " System.out.println(i);\n"
             + "}\n\n"
             + "for (int i = 0; i <= 10; i = i + 2) {\n"
             + "    System.out.println(i);\n"
             + "}";

        final Pattern pattern = Pattern.compile(regex);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: \n" + matcher.group(0));
        }
    }
}

Выход 1

Full match: 
for (int i = 0; i <= 10; i = i + 2) {
 System.out.println(i);
}
Full match: 
for (int i = 0; i <= 10; i = i + 2) {
 System.out.println(i);
}
Full match: 
for (int i = 0; i <= 10; i = i + 2) {
    System.out.println(i);
}

Метод 2

Другим методом может быть использование чередования, собирать нежелательныеfor с, а затем желаемые, возможно, используя выражение, подобное:

\\/\\*[\\s\\S]*?\\*\\/|\\bfor\\b

RegEx Demo 2

Test 2

import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class RegularExpression{

    public static void main(String[] args){

        final String regex = "\\/\\*[\\s\\S]*?\\*\\/|\\bfor\\b";
        final String string = "for (int i = 0; i <= 10; i = i + 2) {\n"
             + " System.out.println(i);\n"
             + "}\n\n"
             + "/*\n"
             + "When you know exactly how many times you want to loop through a block of code, use \n"
             + "the for loop instead of a while loop\n"
             + "***/\n\n"
             + "for (int i = 0; i <= 10; i = i + 2) {\n"
             + " System.out.println(i);\n"
             + "}\n\n"
             + "/****\n"
             + "When you know exactly how many times you want to loop through a block of code, use \n"
             + "the for loop instead of a while loop\n"
             + "*/\n\n"
             + "for (int i = 0; i <= 10; i = i + 2) {\n"
             + "    System.out.println(i);\n"
             + "}\n\n"
             + "/*\n"
             + "When you know exactly how many times you want to loop through a block of code, use \n"
             + "the for loop instead of a while loop\n"
             + "*/";

        final Pattern pattern = Pattern.compile(regex);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: \n" + matcher.group(0));
        }               

    }
}

Вывод 2

Full match: for
Full match: /*
When you know exactly how many times you want to loop through a block of code, use 
the for loop instead of a while loop
***/
Full match: for
Full match: /****
When you know exactly how many times you want to loop through a block of code, use 
the for loop instead of a while loop
*/
Full match: for
Full match: /*
When you know exactly how many times you want to loop through a block of code, use 
the for loop instead of a while loop
*/

Если вы хотите упростить / обновить / изучить выражение, это было объяснено на верхней правой панели regex101.com . Вы можете посмотреть соответствующие шаги или изменить их в этой ссылке отладчика , если вам будет интересно. Отладчик демонстрирует, что движок RegEx может шаг за шагом потреблять некоторые входные строки образца и выполнять процесс сопоставления.


Схема RegEx

jex.im визуализирует регулярные выражения:

enter image description here

0 голосов
/ 23 декабря 2019

Если бы я делал это, я просто написал бы некоторый код, чтобы игнорировать комментарии. Начните игнорировать, когда вы видите / *, и возобновите синтаксический анализ при обнаружении * /.

. Для // вы можете видеть, меньше ли индекс строки "//" в строке, чем индекс "для",Если это не считать для.

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

/*
for (int i = 0; i <= 10; i = i + 2) {
 System.out.println(i);
}
*/

Если вы читаете во всех строкахпрограммы как одной большой строки, а затем обработать ее так, как вы можете сделать это

    // Note: Java 13 text block 
    String program = """
      //This is a for loop 
      for (int i = 0; i <= 10; i = i + 2) {
       System.out.println(i);
      }

      /*
      When you know exactly how many times you want to loop through a block of code, use 
      the for loop instead of a while loop
      */
      """;

  1. Первый replaceAll удаляет все комментарии типа / *.
  2. Второй replaceAll удаляет однострочные комментарии до конца строки
  3. (? S) - это флаг, указывающий разрешенные многострочные совпадения.
     program = program.replaceAll("(?s)/\\*.*\\*/", "")
                      .replaceAll("^(?s)(.*?)//.*?\n","$1");


    int forCount = 0;
    int idx = 0;
    while ((idx =  program.indexOf("for")) >= 0) {
       forCount++;
       program = program.substring(idx+1);
    }
    System.out.println(forCount + " occurence of for found");

Печать

1 вхождение для найденного

Примечание. Вышесказанное работает в крайнем случае, но не очень эффективно и не полно.

Рассмотрим следующий допустимый синтаксис.

    for 
       (
          int intfor = 10;
          intfor < 20;
          intfor++
          ) {}

или

String text = "what is the formula?";

Мой метод не поможет описанному выше. Изящное регулярное выражение может решить эту проблему, но написание синтаксического анализатора для анализа кода на лету, а также разрешение на поиск всех ключевых слов Java было бы способом, и imho, нетривиальным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...