Как удалить комментарии из кода Scala

Есть идеи, как удалить комментарии из кода Scala, чтобы:

  • Вложенные многострочные или однострочные комментарии удаляются.
  • Комментарии внутри строковых литералов не удаляются.
  • В коде могут использоваться литералы с одинарными и тройными кавычками.
  • Строковые литералы могут содержать экранированные символы кавычек.

Вот пример кода с комментариями:

object TestCode {

  val a = "A" // a = "AA"
  val b = "B" /* b = "BB" */
  val c = "C" /* multi line comment
  /* c = "CC" nested */ // FOO
  */ // c = "CCC"
  val d = """D""" // d = """DD /* """
  val e = '"' // e = '"' = char literal
  val f = '\"' // f = '\"' = char literal
  val codeStr = " \"  \"\" \"\"\"/* This is literal */\"\"\" val x = \"\"\"5\"\"\" \" "
  "/* This is a literal */" // This is a comment 3
  "// This is a literal with extra comment end string */" // This is a comment 4
  "/* This is a litral with extra comment begin string" // This is a comment 5

}

Код компилируется (с предупреждениями о чистых выражениях).

Препроцессор C подходит довольно близко, но не справляется с вложенными комментариями.

object TestCode {
  val a = "A"
  val b = "B"
  val c = "C"
  */
  val d = """D"""
  val e = '"'
  val f = '\"'
  val codeStr = " \"  \"\" \"\"\"/* This is literal */\"\"\" val x = \"\"\"5\"\"\" \" "
  "/* This is a literal */"
  "// This is a literal with extra comment end string */"
  "/* This is a litral with extra comment begin string"
}

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

str.replaceAll("//.*|/\\*(?s:.*?)\\*/|(\"(?:(?<!\\\\)(?:\\\\\\\\)*\\\\\"|[^\r\n\"])*\")", "$1")
res1: String = """object TestCode {

  val a = "A" 
  val b = "B" 
  val c = "C"  
  */ 
  val d = """D""" 
  val e = '"' // e = '"' = char literal
  val f = '\"' // f = '\"' = char literal
  val codeStr = " \"  \"\" \"\"\"/* This is literal */\"\"\" val x = \"\"\"5\"\"\" \" "
  "/* This is a literal */" 
  "// This is a literal with extra comment end string */" 
  "/* This is a literal with extra comment begin string" 

}"""

Компилятор Scala может выполнить эту работу, но, насколько я понимаю, у компилятора нет возможности просто удалять комментарии.

Удален тег c++, так как он показался неактуальным.

Guru Stron 26.06.2024 21:17

Я бы использовал scalameta для анализа кода и удаления комментариев из ast. Или используйте собственное правило scalafix.

Mateusz Kubuszok 26.06.2024 22:39

Пробовали ли вы что-нибудь с Scalafix/Scalameta или Wartremover?

Dmytro Mitin 28.06.2024 01:02

@GuruStron Ну, предварительная обработка - это стандартная техника C/C++ :)

Dmytro Mitin 28.06.2024 01:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
87
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я использовал предложение Матеуша Кубушока и использовал ScalaMeta для реализации.

Это файл сценария scala-cli: SourceCodeCommentRemover.scala

//> using scala "2.13.5"
//> using lib "org.scalameta::scalameta:4.9.7"

import scala.meta._
import java.io.{File, PrintWriter}

object CommentRemover {
  def main(args: Array[String]): Unit = {
    if (args.length != 2) {
      println("Usage: CommentRemover <input file> <output file>")
      sys.exit(1)
    }

    val inputFile = new File(args(0))
    val outputFile = new File(args(1))

    if (!inputFile.exists()) {
      println(s"Input file ${inputFile.getAbsolutePath} does not exist.")
      sys.exit(1)
    }

    val sourceCode = {
      import scala.io.Source
      Source.fromFile(inputFile).mkString
    }

    println(s"Original source: BEGIN\n${sourceCode}\nEND")

    val tree = sourceCode.parse[Source] match {
      case parsers.Parsed.Success(tree) => tree
      case parsers.Parsed.Error(_, msg, _) =>
        println(s"Failed to parse the input file: $msg")
        sys.exit(1)
    }

    val codeWithoutComments = tree.tokens.collect {
      case token if !token.is[Token.Comment] => token.text
    }.mkString

    println(s"Comments removed: BEGIN\n${codeWithoutComments}\nEND")

    val writer = new PrintWriter(outputFile)
    try {
      writer.write(codeWithoutComments)
    } finally {
      writer.close()
    }

    println(s"Comments removed. Output written to ${outputFile.getAbsolutePath}.")
  }
}

Это тестовый входной файл: StackOverflowTestCode.scala

object TestCode {

  val a = "A" // a = "AA"
  val b = "B" /* b = "BB" */
  val c = "C" /* multi line comment
  /* c = "CC" nested */ // FOO
  */ // c = "CCC"
  val d = """D""" // d = """DD /* """
  val e = '"' // e = '"' = char literal
  val f = '\"' // f = '\"' = char literal
  val codeStr = " \"  \"\" \"\"\"/* This is literal */\"\"\" val x = \"\"\"5\"\"\" \" "
  "/* This is a literal */" // This is a comment 3
  "// This is a literal with extra comment end string */" // This is a comment 4
  "/* This is a litral with extra comment begin string" // This is a comment 5

}

Запустите скрипт:

scala-cli run SourceCodeCommentRemover.scala -- StackOverflowTestCode.scala out.scala

cat  out.scala

object TestCode {

  val a = "A" 
  val b = "B" 
  val c = "C"  
  val d = """D""" 
  val e = '"' 
  val f = '\"' 
  val codeStr = " \"  \"\" \"\"\"/* This is literal */\"\"\" val x = \"\"\"5\"\"\" \" "
  "/* This is a literal */" 
  "// This is a literal with extra comment end string */" 
  "/* This is a litral with extra comment begin string" 

}

Версия Scala-cli:

scala-cli --version
Scala CLI version: 1.4.1
Scala version (default): 3.4.2

Другие вопросы по теме