2012-04-15 26 views
8

Tôi biết rằng câu hỏi này đã được yêu cầu rồi, nhưng tôi đang tìm trình phân tích cú pháp Java cli với một chức năng cụ thể. Tôi muốn nó có thể xác định cây dòng lệnh, do đó sử dụng các lệnh con (và nhiều độ sâu cấp). Vì vậy, tôi có thể có 3-4 cấp lệnh trước khi tôi nhận được các tùy chọn. Và các tiểu ban này loại trừ lẫn nhau. Cảm ơnJava CLI Parser

+0

Bạn có thể đăng vài ví dụ về các lệnh mà bạn định phân tích cú pháp không? – dash1e

+1

lệnh sub-command sub-sub-command -option1 đối số-đối số-đối số – Sophie

Trả lời

0

Nếu biểu thức lệnh của bạn phức tạp thì bạn có thể nghĩ để xác định cú pháp, viết BNF và sử dụng thư viện như JavaCC hoặc AntLR để tạo trình phân tích cú pháp của riêng bạn.

12

Có thể thực hiện với JCommander. Mỗi đối tượng JCommander, về bản chất, một lệnh với số lượng tham số tùy ý và/hoặc số lượng tùy ý các lệnh con lồng nhau, trong đó đối tượng JCommander trên cùng là lệnh gốc. Các tham số lệnh luôn luôn cụ thể cho lệnh mà chúng đã được khai báo và không can thiệp vào các tham số của các lệnh khác. Giao diện để thêm một tiểu lệnh không phải là rất trực quan nhưng có thể (xem phương pháp addCommand())

Dưới đây là một bằng chứng của khái niệm lớp thử nghiệm:

public class Test{ 

@Test 
public void nestedSubCommandTest() { 
    GeneralOptions generalOpts = new GeneralOptions(); 
    JCommander jc = new JCommander(generalOpts); 

    Command command = new Command(); 
    JCommander jc_command = addCommand(jc, "command", command); 

    SubCommand1 subcommand1 = new SubCommand1(); 
    JCommander jc_subcommand1 = addCommand(jc_command, "subcommand1", 
      subcommand1); 

    SubCommand2 subcommand2 = new SubCommand2(); 
    JCommander jc_subcommand2 = addCommand(jc_subcommand1, "subcommand2", 
      subcommand2); 

    SubCommand3 subcommand3 = new SubCommand3(); 
    addCommand(jc_subcommand2, "subcommand3", subcommand3); 

    jc.parse("--general-opt", 
     "command", "--opt", 
     "subcommand1", 
     "subcommand2", "--sub-opt2", 
     "subcommand3", "--sub-opt3"); 

    assertTrue(generalOpts.opt);// --general-opt was set 
    assertTrue(command.opt);// command --opt was set 
    assertFalse(subcommand1.opt);// subcommand1 --sub-opt1 was not set 
    assertTrue(subcommand2.opt);// subcommand2 --sub-opt2 was set 
    assertTrue(subcommand3.opt);// subcommand3 --sub-opt3 was set 
} 

private static JCommander addCommand(JCommander parentCommand, 
     String commandName, Object commandObject) { 
    parentCommand.addCommand(commandName, commandObject); 
    return parentCommand.getCommands().get(commandName); 
} 

public static class GeneralOptions { 
    @Parameter(names = "--general-opt") 
    public boolean opt; 
} 

@Parameters 
public static class Command { 
    @Parameter(names = "--opt") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand1 { 
    @Parameter(names = "--sub-opt1") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand2 { 
    @Parameter(names = "--sub-opt2") 
    public boolean opt; 
} 

@Parameters 
public static class SubCommand3 { 
    @Parameter(names = "--sub-opt3") 
    public boolean opt; 
} 
} 

Edit: thế nào để sử dụng lại các lệnh.

Giải pháp 1, sử dụng thừa kế:

public class CommonArgs{ 
    @Parameter(names="--common-opt") 
    public boolean isCommonOpt; 
    } 

    @Parameters(description = "my command 1") 
    public class MyCommand1 extends CommonArgs{} 

    @Parameters(description = "my command 2") 
    public class MyCommand2 extends CommonArgs{} 

Tôi nghĩ rằng việc sử dụng và hành vi là faily rõ ràng cho thế này. Một hạn chế là bạn chỉ có thể mở rộng từ một lớp, trong đó có thể giới hạn khả năng sử dụng lại trong tương lai.

Giải pháp 2, sử dụng mô hình thành phần (xem doc here):

public class CommonArgs{ 
    @Parameter(names="--common-opt") 
    public boolean isCommonOpt; 
    } 

    @Parameters(description = "my command 1") 
    public class MyCommand1{ 
    @ParametersDelegate 
    public CommonArgs commonArgs = new CommonArgs(); 
    } 

    @Parameters(description = "my command 2") 
    public class MyCommand2{ 
    @ParametersDelegate 
    public CommonArgs commonArgs = new CommonArgs(); 
    } 

Ở đây, các thông số của lồng nhau commonArgs lớp sẽ được đối xử như thể chúng là các thông số trực tiếp của lớp lệnh. Bạn có thể thêm bao nhiêu đại biểu như bạn muốn, hoặc thậm chí làm tổ đại biểu bên trong các đại biểu khác và như vậy. Để nhận giá trị của tùy chọn được ủy quyền sau khi phân tích cú pháp, chỉ cần thực hiện myCommand1.commonArgs.isCommonOpt, v.v.

+0

Xin chào. Tôi đang chơi với JCommander cả ngày thực sự. Tôi có vài vấn đề với nó. Ngoại lệ của trình phân tích cú pháp không rõ ràng chút nào, tôi không thể giới thiệu chúng với người dùng. Một điều nữa là tôi cần phải tạo một lớp lệnh cho mỗi lệnh (và tôi có rất nhiều), tôi không thể tái sử dụng chúng bởi vì các chú thích không phải là generics. Oh và cách sử dụng() không thực sự in ra tất cả các subcommands và các tùy chọn. – Sophie

+2

JCommander có lẽ không được thiết kế với các lệnh con là ưu tiên hàng đầu, nó có nhiều tính năng * ẩn * hơn, nếu bạn muốn. Không có nhiều trường hợp đặc biệt, vì vậy bạn có thể quấn chúng vào một cái gì đó hữu ích hơn. Đối với 'usage()', không có sự hỗ trợ chính thức của các lệnh con, vì vậy bạn sẽ phải thực hiện một số hack, hoặc chỉ cần viết tay nó. Tôi không thể đồng ý về việc tái sử dụng, mặc dù, khả năng sử dụng lại là điều tôi thích về JCommander. Tôi có thể giúp đỡ về điều đó nếu bạn cho tôi một ví dụ cụ thể. – rodion

+0

Ok. Cảm ơn bạn! Vì vậy, ví dụ tôi có 2 lệnh có cách đặt tên khác nhau và các mô tả khác nhau nhưng cả hai đều có cùng thông số. do đó, để thiết lập mô tả, tôi phải có các trường hợp khác nhau của lớp lệnh mặc dù các parareters bên trong lớp sẽ giống nhau. – Sophie

0

Tôi nghĩ sẽ tốt hơn nếu tách các lệnh đa cấp này thành nhiều công cụ CLI.

Thay vì:
program cmd sub-cmd sub-sub-cmd -option1 argument -option2 argument

Nối một hoặc hai cấp độ chương trình và tên:
program-cmd-sub-cmd sub-sub-cmd -option1 argument -option2 argument

Bất dụ từ:
svn-add -q -N foo.c

Bạn có thể giữ tất cả các lớp học cần thiết trong JAR đơn (và sử dụng lại chúng nhiều như bạn muốn), chỉ cần thêm một số điểm vào "chính". Để phân tích cú pháp CLI cơ bản, tôi cũng khuyên bạn nên JCommander.

1

picocli hỗ trợ các thư mục con lồng nhau đến độ sâu tùy ý.

CommandLine commandLine = new CommandLine(new MainCommand()) 
     .addSubcommand("cmd1", new ChildCommand1()) // 1st level 
     .addSubcommand("cmd2", new ChildCommand2()) 
     .addSubcommand("cmd3", new CommandLine(new ChildCommand3()) // 2nd level 
       .addSubcommand("cmd3sub1", new GrandChild3Command1()) 
       .addSubcommand("cmd3sub2", new GrandChild3Command2()) 
       .addSubcommand("cmd3sub3", new CommandLine(new GrandChild3Command3()) // 3rd 
         .addSubcommand("cmd3sub3sub1", new GreatGrandChild3Command3_1()) 
         .addSubcommand("cmd3sub3sub2", new GreatGrandChild3Command3_2()) 
           // etc 
       ) 
     ); 

Bạn cũng có thể sử dụng trợ giúp về cách sử dụng với kiểu và màu ANSI.

Lưu ý rằng trợ giúp sử dụng liệt kê các tiểu ban được đăng ký ngoài các tùy chọn và tham số vị trí.

enter image description here

Việc sử dụng sự giúp đỡ có thể dễ dàng tùy chỉnh với các chú thích.

enter image description here

  • chú thích dựa trên
  • git kiểu lệnh con
  • lồng sub-lệnh con
  • thông số tùy chọn mạnh mẽ gõ
  • mạnh mẽ gõ tham số vị trí
  • loại chuyển đổi tùy
  • tùy chọn đa giá trị
  • mô hình trực quan cho bao nhiêu đối số một lĩnh vực tiêu thụ
  • thạo API
  • POSIX kiểu nhóm tùy chọn ngắn
  • GNU phong cách tùy chọn dài
  • cho phép bất kỳ tùy chọn tiền tố
  • màu ANSI trong trợ giúp sử dụng
  • trợ giúp sử dụng có thể tùy chỉnh
  • tệp nguồn duy nhất: bao gồm làm nguồn để duy trì ứng dụng của bạn một bình duy nhất