<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Scala正則和抽取器:解析方法參數(shù)

          共 25099字,需瀏覽 51分鐘

           ·

          2021-02-26 10:56

          公眾號關(guān)注 “GitHub今日熱榜
          設(shè)為 “星標(biāo)”,帶你挖掘更多開發(fā)神器!




            


          在《正則表達(dá)式基礎(chǔ)知識》中概括了正則表達(dá)式的基礎(chǔ)知識, 本文講解如何使用正則表達(dá)式解析方法參數(shù),從而可以根據(jù) DAO 自動生成 Service.


          在做 Java 項(xiàng)目時,常常要根據(jù) DAO 生成 Service , 而 Service 有時是簡單的調(diào)用 DAO 方法。比如根據(jù) public CreativeDO findByCreativeId(Long creativeId)  生成如下代碼:


          public CreativeDO findByCreativeId(Long creativeId) {
                return creativeDAO.findByCreativeId(creativeId);
          }


          實(shí)際上就是將分號替換成帶左右大括號的部分, 而 return 語句里可變的部分是方法名稱 (findByCreativeId)、方法列表 (creativeId) , 因此,需要從方法簽名中提取出方法名稱和參數(shù)列表。正則表達(dá)式尤其適合做這件事。 


          編寫正則表達(dá)式的技巧:


          1.  從簡單的表達(dá)式寫起, 反復(fù)試驗(yàn),逐步逼近;

          2.  分而治之:將要匹配的字符串分解成有意義的小組,分別寫出匹配小組的子正則表達(dá)式,然后組合成完整的正則表達(dá)式;   

          3.  為了兼容處理輸入含前導(dǎo)后綴空格的情況,通常在正則表達(dá)式前后添加 \s*Regex\s* 。


          從最簡單的開始


          編寫正則表達(dá)式,從最簡單的開始。先處理只有一個參數(shù)的方法簽名,可以拆解為方法名稱及方法參數(shù)列表兩個部分:


          val methodNameRegexStr = "\\s*(?:\\w+\\s+)?\\w+<?\\w+>?\\s+(\\w+)"
          val singleParamRegexStr = "[^,]*\\w+<?\\w+>?\\s+(\\w+)\\s*"
          val simpleMethodSignRexStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "\\)\\s*;\\s*"


          這里小小地使用到了"分而治之"的技巧。其中:


          1.  帶訪問修飾符或不帶訪問修飾符:CreativeDO findByCreativeId(Long creativeId) 或  public CreativeDO findByCreativeId(Long creativeId) ;  這里使用了  (?:\\w+\\s+)? 來匹配帶 public 或不帶 public 的情況, ? 表示可有可無;(?:regex) 表示匹配 regex 的字符串但是并不捕獲該分組,這是由于只要使用了小括號的正則都會被捕獲,可以在后續(xù)引用匹配結(jié)果,但是這里 public 并不是我們感興趣的目標(biāo),忽略掉;

                

          2.  參數(shù)可能是集合類型: \\w+? , 比如 List, 這里不能匹配嵌套的結(jié)構(gòu), 比如 List<list> 實(shí)際中在 DAO 層也很少出現(xiàn);</list

            

          3.  方法名稱使用了 (\\w+) 來捕獲;

            

          4.  方法參數(shù)中使用  \\w+?  來匹配參數(shù)類型, 比如 Long 或 List;  使用  [^,]* 來匹配參數(shù)類型前面的部分,比如  @Param(\"orderNo\") ;  [^charset] 使用了字符集排除組,排除匹配 charset 指定的任何字符;  [^,]*\\w+?\\s+(\\w+)\\s* 可以匹配 Long creativeId 或 @Param(\"creativeId\")  Long creativeId  ;

               

          5. 合并起來就是  simpleMethodSignRexStr 用來匹配單參數(shù)的方法簽名。


          使用: 在字符串上調(diào)用方法 r 即可獲取對應(yīng)的正則表達(dá)式用來匹配; 使用 regex(values) = text 可以從 text 中抽取匹配 regex 中的分組的值 values 。  


          val methodSign = " int insert(@Param(\"kdtId\") BuyerAddressDO buyerAddressDO); "
          val simpleMethodSignRex = simpleMethodSignRexStr.r
          val simpleMethodSignRex(methodName, arg) = methodSign
          println(methodName + " " + arg)


          處理雙參數(shù)


          有了匹配單參數(shù)方法簽名的正則表達(dá)式, 又有匹配單參數(shù)的正則表達(dá)式, 編寫處理雙參數(shù)的方法簽名就簡單多了:  


          val twoParamMethodSignRegStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "," + singleParamRegexStr + "\\);\\s*"


          這里感受到了正則表達(dá)式復(fù)用的滋味了吧!^_^

               

          使用:   


          val twoParamMethodSign = "OrderExpressDO getById(@Param(\"id\") int id, @Param(\"kdtId\") int kdtId); "
          val twoParamMethodSignRex = twoParamMethodSignRegStr.r
          val twoParamMethodSignRex(methodName2, arg1, arg2) = twoParamMethodSign
          println(List(methodName2, arg1 + ", " + arg2))


          處理任意多個參數(shù)

             

          通常擴(kuò)展下雙參數(shù)情況就可以了?!?/p>


          //val generalParamMethodSignRegStr = methodNameRegexStr + "\\((" + singleParamRegexStr + "(?:," + singleParamRegexStr + ")*)\\);\\s*"


          不過,事實(shí)卻沒有那么美好。即使這樣能夠匹配整個方法簽名,卻只能捕獲第一個參數(shù)和最后一個參數(shù),中間的參數(shù)會被忽略。怎么辦了?查看 Scala 正則表達(dá)式的部分尋找答案,發(fā)現(xiàn)抽取器似乎能夠解決整個問題。


          抽取器


          抽取器并不是什么特別的事物,只是 Scala 增加的一個語法糖,用于從對象值中抽取出感興趣的值或值集合;就好比 Java 里實(shí)現(xiàn)了迭代器方法的對象都可以使用 foreach 遍歷一樣。實(shí)際上, val twoParamMethodSignRex(methodName2, arg1, arg2) = twoParamMethodSign 已經(jīng)使用到了抽取器的語法,這里正則表達(dá)式實(shí)現(xiàn)了抽取器的功能。只要對象實(shí)現(xiàn)了 unapply 或 unapplySeq 就可以使用抽取器語法。對于解析方法簽名這個例子,可以先將參數(shù)列表使用正則表達(dá)式抽取出來,然后用逗號分隔,最后使用單參數(shù)正則表達(dá)式(又一次復(fù)用!) 抽取,實(shí)現(xiàn)如下:


          val generalParamMethodSignRegStr = methodNameRegexStr + "\\((.*)\\);\\s*"
          object Method {

                  def unapplySeq(methodSign:String): Option[(String, Seq[String])] = {
                      try {
                          val generalParamMethodSignReg = generalParamMethodSignRegStr.r
                          val generalParamMethodSignReg(methodName, args)
          = methodSign
                          val params = args.split(',').toList
                          val argNames = params.map(extractArgName(_))
                          println("parsed: " + Some(methodName, argNames))
                          Some(methodName, argNames)
                      } catch {
                          case _ => Some("", List())
                      }

                  }

                  def extractArgName(singleParam: String): String = {
                      val singleParamRegex = singleParamRegexStr.r
                      val singleParamRegex(argName)
          = singleParam
                      return argName
                  }

              }


          然后可以這樣使用:


          generalParamMethodSign match {
                      case Method(methodName, firstArg, restArgs @ _*) =>
                          println("Case Match Way: " + methodName + "(" + firstArg + ", " + restArgs.mkString(", ") + ")")
                      case _ => println("Not matched")
                  }

                  val Method(methodName5, firstArg, restArgs @ _*) = generalParamMethodSign
                  println("Extractor Way: " + methodName5 + "(" + firstArg + ", " + restArgs.mkString(", ") + ")")


          其中:firstArg 是抽取列表的第一個元素, restArgs 是抽取列表的剩余元素。如果寫成  val Method(methodName, args) = generalParamMethodSign 是不行的,估計是因?yàn)榱斜硎峭ㄟ^鏈表的形式實(shí)現(xiàn)的:列表總是第一個元素鏈接到剩余元素的列表。

            

          完整代碼:


          package scalastudy.basic

          import java.io.PrintWriter

          import scalastudy.utils.DefaultFileUtil._
          import scalastudy.utils.PathConstants

          /**
           * Created by shuqin on 16/4/22.
           */

          object AutoGenerateJavaCodes extends App {

              val methodNameRegexStr = "\\s*(?:\\w+\\s+)?\\w+<?\\w+>?\\s+(\\w+)"
              val singleParamRegexStr = "[^,]*\\w+<?\\w+>?\\s+(\\w+)\\s*"
              val simpleMethodSignRexStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "\\)\\s*;\\s*"
              val twoParamMethodSignRegStr = methodNameRegexStr + "\\(" + singleParamRegexStr + "," + singleParamRegexStr + "\\);\\s*"
              //val generalParamMethodSignRegStr = methodNameRegexStr + "\\((" + singleParamRegexStr + "(?:," + singleParamRegexStr + ")*)\\);\\s*"
              val generalParamMethodSignRegStr = methodNameRegexStr + "\\((.*)\\);\\s*"

              val apiPackageName = "cc.lovesqcc"

              launch()


              object Method {

                  def unapplySeq(methodSign:String): Option[(String, Seq[String])] = {
                      try {
                          val generalParamMethodSignReg = generalParamMethodSignRegStr.r
                          val generalParamMethodSignReg(methodName, args) = methodSign
                          val params = args.split(',').toList
                          val argNames = params.map(extractArgName(_))
                          println("parsed: " + Some(methodName, argNames))
                          Some(methodName, argNames)
                      } catch {
                          case _ => Some("", List())
                      }

                  }

                  def extractArgName(singleParam: String): String = {
                      val singleParamRegex = singleParamRegexStr.r
                      val singleParamRegex(argName) = singleParam
                      return argName
                  }

              }

              def generateJavaFile(filepath: String): List[Any] = {

                  val basePath = "/tmp/"
                  val biz = List("order", "payment")

                  var writePath = basePath
                  var bizType = ""
                  biz.foreach { e =>
                      if (filepath.contains(e)) {
                          writePath = writePath + "/" + e + "/"
                          bizType = e
                      }
                  }
                  val daoFileName = extraFilename(filepath)
                  val daoClassName = daoFileName.substring(0, daoFileName.indexOf('.'))
                  val writeFilename = writePath + daoFileName.replaceAll("DAO", "ServiceImpl")
                  val serviceClassName = daoClassName.replace("DAO", "ServiceImpl")
                  val daoRefName = firstLower(daoClassName)
                  val lines = readFileLines(filepath)
                  var fileContents = ""
                  var daoFlag = false
                  lines.foreach { line =>
                      if (daoFlag) {
                          fileContents += "\n\t@Resource\n"
                          fileContents += "\tprivate " + daoClassName + " " + daoRefName + ";\n\n"
                          daoFlag = false
                      }
                      else if (line.contains("interface")) {
                          fileContents += "@Service\npublic class " + serviceClassName + " implements " + daoClassName.replace("DAO", "Service") + " { \n"
                          daoFlag = true
                      }
                      else if (line.contains(";")) {
                          if (!line.contains("import") && !line.contains("package")) {
                              val parsed = parseMethod(line)
                              val replaceStr = " {\n\t\treturn " + daoRefName + "." + parsed(0) + "(" + parsed(1) + ");\n\t}\n"
                              var assertQualifier = ""
                              if (!line.contains("public")) {
                                  assertQualifier = "public "
                              }
                              fileContents += "\t" + assertQualifier + " " + line.trim.replace(";", replaceStr)
                          }
                          else if (line.contains("package")) {
                              fileContents += line.replace("dao", "service") + "\n\n"
                              var bizTypeStr = "."
                              if (bizType.length > 0) {
                                  bizTypeStr = "." + bizType + "."
                              }
                              fileContents += "import " + apiPackageName + bizTypeStr + "service." + daoClassName.replace("DAO", "Service") + ";\n"
                              fileContents += "import javax.annotation.Resource;\n"
                              fileContents += "import org.springframework.stereotype.Service;\n"
                          }
                          else {
                              fileContents += line + "\n"
                          }
                      }
                      else {
                          fileContents += line + "\n"
                      }
                  }

                  mkdir(writePath)
                  val writeFile = new PrintWriter(writeFilename)
                  writeFile.println(fileContents)
                  writeFile.close

                  return List[Any]();
              }

              def daoRefName(daoClassName: String): String = {
                  return firstLower(daoClassName)
              }

              def firstLower(str: String): String = {
                  return str.charAt(0).toLower + str.substring(1)
              }

              def parseMethod(methodSign: String): List[String] = {

                  val simpleMethodSignRex = simpleMethodSignRexStr.r
                  try {
                      val Method(methodName, firstArg, restArgs @ _*) = methodSign
                      if (restArgs.size == 0) {
                          return List(methodName, firstArg)
                      }
                      else {
                          return List(methodName, firstArg + ", " + restArgs.mkString(", "))
                      }

                  } catch {
                      case _ => return List("", "")
                  }


              }


              def debug(): Unit = {

                  // simple catch regex groups
                  val methodSign = " int insert(@Param(\"kdtId\") BuyerAddressDO buyerAddressDO); "
                  val simpleMethodSignRex = simpleMethodSignRexStr.r
                  val simpleMethodSignRex(methodName, arg) = methodSign
                  println(methodName + " " + arg)

                  val twoParamMethodSign = "OrderExpressDO getById(@Param(\"id\") int id, @Param(\"kdtId\") int kdtId); "
                  val twoParamMethodSignRex = twoParamMethodSignRegStr.r
                  val twoParamMethodSignRex(methodName2, arg1, arg2) = twoParamMethodSign
                  println(List(methodName2, arg1 + ", " + arg2))

                  val text = "Good query(@Param(\"goodId\") goodId, int kdtId)"
                  val regex = "\\s*(?:\\w+\\s+)?\\w+<?\\w+>?\\s+(\\w+)\\((.*)\\)".r
                  val regex(methodName3, wholearg1) = text
                  println(methodName3 + " " + wholearg1);

                  val generalParamMethodSign = " OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, @Param(\"page\") Integer page, @Param(\"pageSize\") Integer pageSize, boolean flag); "
                  val regex2 = generalParamMethodSignRegStr.r
                  val regex2(methodName4, wholearg2) = generalParamMethodSign
                  println(methodName4 + " : " + wholearg2);

                  generalParamMethodSign match {
                      case Method(methodName, firstArg, restArgs @ _*) =>
                          println("Case Match Way: " + methodName + "(" + firstArg + ", " + restArgs.mkString(", ") + ")")
                      case _ => println("Not matched")
                  }

                  val Method(methodName5, firstArg, restArgs @ _*) = generalParamMethodSign
                  println("Extractor Way: " + methodName5 + "(" + firstArg + ", " + restArgs.mkString(", ") + ")")
              }

              def testParseMethod(): Unit = {
                  val testMethods = Map(
                      " List<OrderDO> queryOrder(int kdtId); " -> List("queryOrder", "kdtId"),
                      " List<OrderDO> queryOrder( int kdtId ); " -> List("queryOrder", "kdtId"),
                      " OrderDO queryOrder(@Param(\"kdtId\") int kdtId); " -> List("queryOrder", "kdtId"),
                      " List<OrderDO> queryOrder(List<String> orderNos); " -> List("queryOrder", "orderNos"),
                      " List<OrderDO> queryOrder(@Param(\"orderNos\") List<String> orderNos); " -> List("queryOrder", "orderNos"),
                      " OrderDO queryOrder(String orderNo, Integer kdtId); " -> List("queryOrder", "orderNo, kdtId"),
                      " OrderDO queryOrder(String orderNo, @Param(\"kdtId\") Integer kdtId); " -> List("queryOrder", "orderNo, kdtId"),
                      " OrderDO queryOrder(@Param(\"orderNo\") String orderNo, Integer kdtId); " -> List("queryOrder", "orderNo, kdtId"),
                      " OrderDO queryOrder(@Param(\"orderNo\") String orderNo, @Param(\"kdtId\") Integer kdtId); " -> List("queryOrder", "orderNo, kdtId"),
                      " OrderDO queryOrder(List<String> orderNos, Integer kdtId); \n" -> List("queryOrder", "orderNos, kdtId"),
                      " OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, Integer kdtId); " -> List("queryOrder", "orderNos, kdtId"),
                      " OrderDO queryOrder(List<String> orderNos, @Param(\"kdtId\") Integer kdtId); " -> List("queryOrder", "orderNos, kdtId"),
                      " OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, @Param(\"kdtId\") Integer kdtId); " -> List("queryOrder", "orderNos, kdtId"),
                      " OrderDO queryOrder(@Param(\"orderNos\") List<String> orderNos, @Param(\"page\") Integer page, @Param(\"pageSize\") Integer pageSize); " -> List("queryOrder", "orderNos, page, pageSize"))
                  testMethods.foreach { testMethod =>
                      println("test method: " + testMethod._1)
                      val parsed = parseMethod(testMethod._1)
                      println(parsed)
                      assert(parseMethod(testMethod._1) == testMethod._2)
                  }
                  println("test ParseMethod passed.")
              }

              def launch(): Unit = {

                  debug
                  testParseMethod

                  val dirpath = "/tmp/";
                  handleFiles(fetchAllFiles)((file: String) => file.endsWith("DAO.java"))(List(generateJavaFile(_)))((liststr: List[Any]) => "")(dirpath);
              }

          }



          出處:cnblogs.com/lovesqcc/p/5450238.html








          關(guān)注GitHub今日熱榜,專注挖掘好用的開發(fā)工具,致力于分享優(yōu)質(zhì)高效的工具、資源、插件等,助力開發(fā)者成長!







          點(diǎn)個在看 你最好看










          瀏覽 60
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91精品人妻少妇无码影院 | 一级片黄色视频 | 国产精品嫩草影院 | 日本A∨在线 | 无码艹逼 |