2015-10-29 3 views
2

У меня есть строка в скрипте python, которая содержит код java.
Как я могу извлечь имя класса базы Java из него, чтобы выполнить его, используя subprocess?
Я думаю, что это может быть достигнуто с помощью регулярного выражения, но я не знаю, как это сделать.
Извлечение имени основного класса java в python

Пример:

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"); 
    } 
} 
""" 
+0

Итак, где же строка? –

+0

Покажите свой код и что не работает. – RobertB

+0

Я просто хотел извлечь имя класса, в котором есть основной метод, чтобы запустить команду 'javac', используя подпроцесс. – user2444327

ответ

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)] 
+0

Извините, что я только что ушел :) –

+0

Он не работает, если я печатаю 'i' внутри цикла, он печатает весь код. – user2444327

+0

@ user2444327 Не печатайте 'i'. Как я уже сказал в своем ответе, 'print (re.search ('class (\ w *)', i) .группа (1)) '. –

0

Вот грубый способ:

import re 

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

... который по существу берет на себя все слова, и найти первое слово после первого появления "класса". Он также удаляет «{» и что-нибудь после того, как он, если у Вас есть ситуация как

class MyClass{ 

Однако вам нужно будет сделать намного больше, если у вас есть несколько классов в файле.

+0

Пробел является необязательным после имени класса, так как это вполне законный и обычный 'класс MyClass {....', поэтому ваш метод не удастся в значительном числе случаев. –

2

Основной класс - это класс, который содержит основную функцию public static void.

Если это возможно в вашей среде; Вы можете использовать библиотеку, которая может анализировать исходный код Java, такие как plyj или javalang:

#!/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' 

Если есть пакет декларация, например, package your_package; в верхней части источника, т.е. Java, если полное имя класса your_package.second затем вы можете получить имя пакета как tree.package.name.

Или вы можете использовать генератор синтаксического анализатора, такой как grako, и указать подмножество грамматики Java, которое достаточно для получения имени класса в вашем случае. Если вход очень регулярный; вы можете попробовать регулярное выражение и ожидать его сбой, если ваши предположения о структуре кода неверны.

+0

кажется, что это работает, но мне было интересно, не слишком ли это излишне. Также достаточно быстро, как регулярное выражение? – user2444327

+0

@ user2444327: все зависит. Измерьте производительность времени и посмотрите, достаточно ли она в вашем случае. Это может быть чрезмерным, но если ограничений на зависимости нет, тогда добавить 'javalang' в свой' requirements.txt' проще, использовать код, который я предоставил, и забыть об этом. С другой стороны, если ввод прост, тогда напишите простое регулярное выражение и разложите его, если необходимо, в каждом конкретном случае. – jfs

1

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

  1. Имя класса не может прекратить с пробелами, поскольку MyClass{ является законным и общим
  2. Параметр типа может быть представлена ​​после имени класса, таких как MyClass<T> а имя Составитель .class файла не будет осуществляться этим параметром типа
  3. файл может иметь более одного высшего класса на уровне, однако один не должен быть объявлен общественности и этот класс не может иметь такое же имя, что и файл
  4. The общественный класс t hat имеет то же имя, что и файл может иметь внутренний класс (который может даже быть открытым), но они обязательно должны появиться после объявления внешнего класса.

Эти советы приводят к поиску первого вхождения фразы public class, захватывая при следующем запуске символов, а затем ищет пробелы, { или < характер.

Это то, что я придумал (может быть немного некрасиво): public\s*(?:abstract?)?\s*(?:static?)?\s*(?:final?)?\s*(?:strictfp?)?\s*class\s*(\w.*)\s*,?<.*$

+0

не обязательно, чтобы класс был общедоступным (как показывает пример кода в вопросе), вы могли бы даже иметь [несколько классов с методом public static main() ') (http://stackoverflow.com/a/ 2324915) – jfs

+0

@ JFSebastian да, это правда. Но как вы можете выполнить этот файл с помощью 'subprocess', потому что не было бы способа получить имя файла из этого исходного кода? Имя файла всегда будет таким же, как и открытый класс в этом файле, и выполнение этого файла приведет к вызову 'main' независимо от того, в каком классе он находится. –

+0

щелкните по ссылке. В нем явно показан пример того, как вы можете выполнять код в таких случаях. Во всяком случае, источник не находится ни в одном файле в случае OPs. – jfs

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) {} 
} 

Вы получаете идею ... Regex всегда может вводить в заблуждение, полагая, что они нашли то, что не является на самом деле то, что вы ищете. Вы должны полагаться на более сложные библиотеки для синтаксического анализа.

Я бы пошел с ответом Дж. Ф. Себастьяна.

Смежные вопросы