Java: удаление комментариев из строки - PullRequest
4 голосов
/ 25 декабря 2011

Я хотел бы сделать функцию, которая получает строку и, если у нее есть встроенные комментарии, она удаляет ее.Я знаю, это звучит довольно просто, но я хочу убедиться, что я делаю это правильно, например:

private String filterString(String code) {
  // lets say code = "some code //comment inside"

  // return the string "some code" (without the comment)
}

Я подумал о двух способах: не стесняйтесь советовать в противном случае

  1. ПовторениеСтрока и поиск двойных строковых скобок и использование метода подстроки.
  2. regex way .. (я не уверен в этом)

Можете ли вы сказать мне, что лучше, и показать мне, какэто должно быть сделано?(пожалуйста, не советуйте слишком продвинутым решениям)

отредактировано: это можно как-то сделать с помощью объекта Scanner?(я все равно использую этот объект)

Ответы [ 7 ]

7 голосов
/ 06 декабря 2013

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

replaceAll("(?:/\\*(?:[^*]|(?:\\*+[^*/]))*\\*+/)|(?://.*)",""));

источник: http://ostermiller.org/findcomment.html

EDIT:

Другое решение, если вы не уверены в использовании регулярных выражений, - это сконструировать небольшой автомат, как показано ниже:

public static String removeComments(String code){
    final int outsideComment=0;
    final int insideLineComment=1;
    final int insideblockComment=2;
    final int insideblockComment_noNewLineYet=3; // we want to have at least one new line in the result if the block is not inline.

    int currentState=outsideComment;
    String endResult="";
    Scanner s= new Scanner(code);
    s.useDelimiter("");
    while(s.hasNext()){
        String c=s.next();
        switch(currentState){
            case outsideComment: 
                if(c.equals("/") && s.hasNext()){
                    String c2=s.next();
                    if(c2.equals("/"))
                        currentState=insideLineComment;
                    else if(c2.equals("*")){
                        currentState=insideblockComment_noNewLineYet;
                    }
                    else 
                        endResult+=c+c2;
                }
                else
                    endResult+=c;
                break;
            case insideLineComment:
                if(c.equals("\n")){
                    currentState=outsideComment;
                    endResult+="\n";
                }
            break;
            case insideblockComment_noNewLineYet:
                if(c.equals("\n")){
                    endResult+="\n";
                    currentState=insideblockComment;
                }
            case insideblockComment:
                while(c.equals("*") && s.hasNext()){
                    String c2=s.next();
                    if(c2.equals("/")){
                        currentState=outsideComment;
                        break;
                    }

                }

        }
    }
    s.close();
    return endResult;   
}
5 голосов
/ 25 декабря 2011

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

private String filterString(String code) {
  String partialFiltered = code.replaceAll("/\\*.*\\*/", "");
  String fullFiltered = partialFiltered.replaceAll("//.*(?=\\n)", "")
}
3 голосов
/ 25 декабря 2011

Просто используйте метод replaceAll из класса String в сочетании с простым регулярным выражением .Вот как это сделать:

import java.util.*;
import java.lang.*;

class Main
{
        public static void main (String[] args) throws java.lang.Exception
        {
                String s = "private String filterString(String code) {\n" +
"  // lets say code = \"some code //comment inside\"\n" +
"  // return the string \"some code\" (without the comment)\n}";

                s = s.replaceAll("//.*?\n","\n");
                System.out.println("s=" + s);

        }
}

Ключом является строка:

s = s.replaceAll("//.*?\n","\n");

Регулярное выражение //. *? \ N соответствует строкам, начинающимся с // до конца строки.

И если вы хотите увидеть этот код в действии, перейдите сюда: http://www.ideone.com/e26Ve

Надеюсь, это поможет!

3 голосов
/ 25 декабря 2011

Найти подстроку перед постоянной подстрокой с использованием замены регулярного выражения - это немного.

Вы можете сделать это, используя indexOf(), чтобы проверить позицию начала комментария, и substring(), чтобы получитьпервая часть, что-то вроде:

String code = "some code // comment";
int    offset = code.indexOf("//");

if (-1 != offset) {
    code = code.substring(0, offset);
}
1 голос
/ 12 января 2017

@ Кристиан Хухер правильно указал, что многие или все опубликованные решения потерпели неудачу, если комментарии встречаются в строке.

@ Loïc Gammaitoni предполагает, что его автоматный подход может быть легко расширен для обработки этого случая. Вот это расширение.

enum State { outsideComment, insideLineComment, insideblockComment, insideblockComment_noNewLineYet, insideString };

public static String removeComments(String code) {
  State state = State.outsideComment;
  StringBuilder result = new StringBuilder();
  Scanner s = new Scanner(code);
  s.useDelimiter("");
  while (s.hasNext()) {
    String c = s.next();
    switch (state) {
      case outsideComment:
        if (c.equals("/") && s.hasNext()) {
          String c2 = s.next();
          if (c2.equals("/"))
            state = State.insideLineComment;
          else if (c2.equals("*")) {
            state = State.insideblockComment_noNewLineYet;
          } else {
            result.append(c).append(c2);
          }
        } else {
          result.append(c);
          if (c.equals("\"")) {
            state = State.insideString;
          }
        }
        break;
      case insideString:
        result.append(c);
        if (c.equals("\"")) {
          state = State.outsideComment;
        } else if (c.equals("\\") && s.hasNext()) {
          result.append(s.next());
        }
        break;
      case insideLineComment:
        if (c.equals("\n")) {
          state = State.outsideComment;
          result.append("\n");
        }
        break;
      case insideblockComment_noNewLineYet:
        if (c.equals("\n")) {
          result.append("\n");
          state = State.insideblockComment;
        }
      case insideblockComment:
        while (c.equals("*") && s.hasNext()) {
          String c2 = s.next();
          if (c2.equals("/")) {
            state = State.outsideComment;
            break;
          }
        }
    }
  }
  s.close();
  return result.toString();
}
0 голосов
/ 10 июля 2015

Я сделал библиотеку с открытым исходным кодом (на GitHub) для этой цели, ее под названием CommentRemover можно удалить однострочными и многострочными комментариями Java.

Поддерживает удаление или НЕ удаление TODO.
Также он поддерживает JavaScript, HTML, CSS, Properties, JSP и XML Comments.

Небольшой фрагмент кода, как его использовать (есть 2 типа использования):

Первый способ InternalPath

 public static void main(String[] args) throws CommentRemoverException {

 // root dir is: /Users/user/Projects/MyProject
 // example for startInternalPath

 CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
        .removeJava(true) // Remove Java file Comments....
        .removeJavaScript(true) // Remove JavaScript file Comments....
        .removeJSP(true) // etc.. goes like that
        .removeTodos(false) //  Do Not Touch Todos (leave them alone)
        .removeSingleLines(true) // Remove single line type comments
        .removeMultiLines(true) // Remove multiple type comments
        .startInternalPath("src.main.app") // Starts from {rootDir}/src/main/app , leave it empty string when you want to start from root dir
        .setExcludePackages(new String[]{"src.main.java.app.pattern"}) // Refers to {rootDir}/src/main/java/app/pattern and skips this directory
        .build();

 CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
                  commentProcessor.start();        
  }

Второй способ ExternalPath

 public static void main(String[] args) throws CommentRemoverException {

 // example for externalPath

 CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
        .removeJava(true) // Remove Java file Comments....
        .removeJavaScript(true) // Remove JavaScript file Comments....
        .removeJSP(true) // etc..
        .removeTodos(true) // Remove todos
        .removeSingleLines(false) // Do not remove single line type comments
        .removeMultiLines(true) // Remove multiple type comments
        .startExternalPath("/Users/user/Projects/MyOtherProject")// Give it full path for external directories
        .setExcludePackages(new String[]{"src.main.java.model"}) // Refers to /Users/user/Projects/MyOtherProject/src/main/java/model and skips this directory.
        .build();

 CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
                  commentProcessor.start();        
  }
0 голосов
/ 25 декабря 2011

для сканера, используйте разделитель,

пример разделителя.

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;

public class MainClass {
  public static void main(String args[]) throws IOException {
FileWriter fout = new FileWriter("test.txt");
fout.write("2, 3.4,    5,6, 7.4, 9.1, 10.5, done");
fout.close();

FileReader fin = new FileReader("Test.txt");
Scanner src = new Scanner(fin);
// Set delimiters to space and comma.
// ", *" tells Scanner to match a comma and zero or more spaces as
// delimiters.

src.useDelimiter(", *");

// Read and sum numbers.
while (src.hasNext()) {
  if (src.hasNextDouble()) {
    System.out.println(src.nextDouble());
  } else {
    break;
  }
}
fin.close();
  }
}

Используйте токенизатор для нормальной строки

tokenizer:

// start with a String of space-separated words
String tags = "pizza pepperoni food cheese";

// convert each tag to a token
StringTokenizer st = new StringTokenizer(tags," ");

while ( st.hasMoreTokens() )
{
  String token = (String)st.nextToken();
  System.out.println(token);
}

http://www.devdaily.com/blog/post/java/java-faq-stringtokenizer-example
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...