在python中提取java主类名

时间:2015-10-29 17:02:58

标签: python regex subprocess

我在python脚本中有一个字符串,其中包含一些java代码。
如何从中提取基类java类名,以便使用subprocess执行它?  我认为它可以使用正则表达式实现,但我不知道如何。

样品:

a = """
import java.util.Scanner;
class sample{}
class second
{
    static boolean check_prime(int a)
    {
        int c=0;
        for (int i=1;i<=a; i++) {
            if(a%i==0)
                c++;
        }
        if(c == 2)
            return true;
        else
            return false;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter two numbers");
        int a = in.nextInt();
        int b = in.nextInt();
        if(check_prime(a) && check_prime(b))
        {
            if(b-a==2 || a-b==2)
                System.out.println("They are twin primes");
            else
                System.out.println("They are not twin primes");
        }
        else
            System.out.println("They might not be prime numbers");
    }
}
"""

5 个答案:

答案 0 :(得分:2)

  

主类是一个包含public static void main函数的类。

如果在您的环境中可行;您可以使用可以解析Java源代码的库,例如plyjjavalang

#!/usr/bin/env python
import javalang # $ pip install javalang

tree = javalang.parse.parse(java_source)
name = next(klass.name for klass in tree.types
            if isinstance(klass, javalang.tree.ClassDeclaration)
            for m in klass.methods
            if m.name == 'main' and m.modifiers.issuperset({'public', 'static'}))
# -> 'second'

如果在Java源代码顶部有一个包声明,例如package your_package;,即如果完整的类名是your_package.second,那么您可以将包名称设为tree.package.name

或者您可以使用解析器生成器(如grako)并指定足以在您的案例中获取类名的Java语法子集。如果输入是高度规则的;如果你对代码结构的假设是错误的,你可以试试一个正则表达式并期望它失败。

答案 1 :(得分:1)

正如您猜测的那样,使用正则表达式可以对问题进行近似解决。但是,要记住一些技巧:

  1. 类名称不能以空格终止,因为MyClass{是合法且通用的
  2. 类名参数可以在MyClass<T>等类名称之后提供,编译的.class文件名称不受此类型参数的影响
  3. 一个文件可能有多个顶级类,但是不能将其声明为public且该类不能与文件同名
  4. 与文件同名的公共类可能有内部类(甚至可能是公共类),但这些必须在外部类声明之后。
  5. 这些提示会导致搜索短语public class的第一次出现,捕获下一轮字符,然后查找空格,{<字符。

    这是我提出的(可能有点难看):public\s*(?:abstract?)?\s*(?:static?)?\s*(?:final?)?\s*(?:strictfp?)?\s*class\s*(\w.*)\s*,?<.*$

答案 2 :(得分:1)

仅使用正则表达式几乎不会起作用。作为其不能的基本示例,请考虑以下事项:

public class A {
     public static void ImDoingThisToMessYouUp () {
          String s = "public static void main (String[] args) {}";
     }
}

public class B {
      public static void main (String[] args) {}
}

你明白了......正则表达式可能总是被愚弄相信他们找到的东西并不是你想要的东西。您必须依赖更高级的库进行解析。

我会选择J.F.Sebastian的回答。

答案 3 :(得分:0)

这是一种粗暴的方式:

import re

b = a.split()
str = b[b.index("class")+1]
javaclass = re.sub("{.*$","",str)
print (javaclass)

...基本上接受所有单词,并在第一次出现“class”后找到第一个单词。如果您遇到类似

的情况,它还会删除“{”及其后的任何内容
class MyClass{

但是,如果文件中有多个类,则需要执行更多操作。

答案 4 :(得分:0)

正如我在评论中所说,使用re.findall()这样:

re.findall('class (\w*)', a)

作为函数名称,findall()可以找到所有类名。此处使用\w将匹配所有ascii字母(如果您使用.*,则优于class MyClass{。)

关于查找主要课程,请使用re.S,如下所示:

for i in re.split('\nclass ', a)[1:]:                      # will match the main code block and the class name of all classes
    if re.search('\n\s*public static void main', i):              # check if 'public static void main' in a class
        print(re.search('(\w*)', i).group(1))       # and print out the class name

更简单的方法,只有一行使用列表理解:

[re.search('(\w*)', i).group(1) for i in re.split('\nclass ', a) if re.search('\n\s*public static void main', i)]