0

我的 Java 非常生疏,我一直在尝试制作一个用户界面,以简化 shell 脚本或批处理文件的执行,具体取决于它是分别是 Linus 还是 Win32。这些文件具有以下命名约定。

  module-verb-object-etc [args-list]
  mysql-connect-grid
  mysql-connect-rds
  mysql-dump-grid
  mysql-dump-grid-se314

最终我希望它解析明确的术语,以便我可以:

  1. 标记命令(例如用“-”分隔)并将它们缩短为简化的术语,例如 foxpro 的命令窗口或 cisco 的 IOS(例如,“my co gr”在 unix 中执行“mysql-connect-grid”,在 win32 中执行 *.cmd)
  2. 并且以 IOS 的风格允许用户输入缩写命令,以便他们可以输入问号 (?),它会提示他们唯一的剩余(或下一个)命令选项(例如“我的?”返回 mysql & "my ?" 返回连接或转储)。对于不唯一或无法匹配的命令,其他返回值将是“不明确的”或“未知的”。这可能看起来微不足道,但每个文件夹中有数百个命令,我的用户不想思考......

我编写了一个函数来从目录中提取文件列表并重新调整文件数组。然后我使用下面的方法将其转换为二维数组,该方法返回一个动态大小的潜在命令网格。

    /**********************************************************************************
     *  MAKE GRID: Parses array of filenames and tokenizes AWS cmds.
     * @param strs  Array of filenames
     **********************************************************************************/
     public static String [][] makeGrid(String strs[], boolean bPrint) {
       String tmpGrid[][];
       int nMaxCols = 0;
       int nRows = uniqueCount(strs);
       int nGridRow = 0; 
       tmpGrid = new String [nRows][]; 
       for (int nRow=0; nRow<nRows; nRow++) { 
 String cFilename = strs[nRow];
                if (!cFilename.endsWith(".cmd") // just list unix files (filter for batch files)
    && cFilename.indexOf("-") > 0 ) // make sure there's a dash in the filename
    {
           String strTokens[] = tokenize(strs[nRow], "-"); // the dash is our token deliminator
           int nCols = strTokens.length; 
           if (nCols>nMaxCols) nMaxCols=nCols;
           tmpGrid[nGridRow] = new String [nCols];
           for (int nCol=0; nCol<nCols; nCol++) { 
               tmpGrid[nGridRow][nCol] = strTokens[nCol];
               if (bPrint) System.out.print(" "+tmpGrid[nGridRow][nCol]);
             }
            nGridRow++;
            if (bPrint) System.out.println("");
     } //end-if
         }
       String[][] cmdGrid = new String[nGridRow][nMaxCols];
       System.arraycopy(tmpGrid, 0, cmdGrid, 0, nGridRow); // removes null rows  (&NPEs!)
       return cmdGrid;
      }

这将返回一个二维数组(如下),grid[Row-N][Col-0]匹配也是如此。我只想提取row[0]通配符匹配为cmdToken[0] && row[1]“like”的不同值,cmdToken[1]以便我的用户可以拼凑一个命令直到"my du gr ?"返回"ENTER, [se314]"- 如果这有意义的话......

String[][] makeGrid:
    mysql dump grid se314
    mysql connect grid
    mysql dump grid
    mysql connect rds

我的挑战:我似乎无法理解我在 java 中的 matcher 函数。如果是 SQL,它将类似于:

"SELECT DISTINCT col2 FROM cmd_Grid
   WHERE col1 LIKE 'cmdToken1%' " 

甚至更好:递归地为每个连续列设置一个 int depthmark

`SELECT DISTINCT col+str(depthmark+1) FROM cmd_Grid 
    WHERE col+str(depthmark) LIKE 'cmdMatchedTokens%' " 

直到你有一个完全匹配。

我发现了一个名为 joSQL 的包,我绝望地尝试了它,但我似乎无法让它在 Java6 中工作。无论如何:我也希望有一个纯 Java 解决方案,以便所有内容都可以包含在一个类中......

也许使用扫描仪或其他东西来解析我的多维数组以获得唯一值......我知道我可能让它变得比它需要的更复杂。

向正确方向轻推将不胜感激。

TIA

4

3 回答 3

1

您还可以考虑使用一些更高级的数据结构,例如 ArrayList 而不是数组,并使用 StringTokenizer 动态生成每个命令 Part。

它会是这样的:

ArrayList<String> matchingCommands = new ArrayList<String>();

    ArrayList<String> commandList = new ArrayList<String>();
    commandList.add("mysql dump grid se314");
    commandList.add("mysql connect grid");
    commandList.add("mysql dump grid");
    commandList.add("mysql connect rds");

    String queryCommand = "my du gr ?";

    for(int i=0; i<commandList.size(); i++)
    {
        boolean matches = false;
        String command = commandList.get(i);
        StringTokenizer commandTokenizer = new StringTokenizer(command, " "); // Using space as the deliminator
        StringTokenizer queryTokenizer = new StringTokenizer(queryCommand, " "); // Using space as the deliminator

        while(commandTokenizer.hasMoreTokens())
        {
            String queryPart = queryTokenizer.nextToken();
            String commandPart = commandTokenizer.nextToken();
            if(commandPart.startsWith(queryPart) || queryPart.equals("?")){
                matches = true;
            }else{
                matches = false;
                break;
            }
        }
        if(matches){
            matchingCommands.add(command);
        }
    }
    System.out.println(matchingCommands);

这将确保您的程序可以动态增长,并且不会因为空对象而浪费内存。

于 2010-01-19T17:47:13.403 回答
0

现在,我正在为每个 cmdString (查询)解析空格分隔符并标记数组。就像是:

 Scanner sCmdString = new Scanner(cInput);
 while (sCmdString.hasNext()) { 
 String cToken = sCmdString.next().toUpperCase().trim();
 System.out.println(" "+cToken+" ");
 // match cmdString[i..n] to cmdGrid
 for (int nRow=0; nRow < cmdGrid.length; nRow++) {
       for (int nCol=0; nCol < cmdGrid[nRow].length; nCol++) {
  if (cmdGrid[nRow][nCol].equalsIgnoreCase(cToken) )
     System.out.println("MATCH: "+cmdGrid[nRow][nCol]);
  else System.out.println("NO MATCH:"+cmdGrid[nRow][nCol].toUpperCase()+":"+cToken+"...");
        }
   }
   }

但我得到了行长不均匀的 NPE。

我喜欢你把列弄平的想法。

我想我仍然必须删除重复项......不是吗?

于 2010-01-19T02:13:03.817 回答
0

一个详尽的解决方案可能是构建一个 hashMap,以便键是一个可能的短命令,如“my co gr”,相应的值是“mysql-connect-grid”。因此哈希映射中的值将具有“ mysql-connect-grid”作为值。

但只有当可能的密钥数量有限时,这才是可行的解决方案。如果不是这种情况,那么您可以使用内置的字符串解析方法。

例如:

    String[][] makeGrid = new String[][]{{"mysql", "dump", "grid", "se314"}, 
              {"mysql", "connect", "grid", ""},
              {"mysql",  "dump", "grid", ""},
              {"mysql", "connect", "rds", ""}
              };
     String[] query2 = new String[]{"my", "du", "gr"};

  String[][] matchingCommands = new String[4][4];
  int resultSize = 0;
     for(int i=0; i<makeGrid.length; i++)
  {
      String[] commandColumn = makeGrid[i];
   boolean matches = false;
      for(int cnt=0; cnt<commandColumn.length; cnt++)
      {
       String commandPart = commandColumn[cnt];
       if(cnt < query2.length){
        String queryPart = query2[cnt];
     if(commandPart.startsWith(queryPart) || queryPart.equals("?")){
         matches = true;
        }else{
         matches = false;
         break;
        }
       }
      }
      if(matches){
       matchingCommands[resultSize] = commandColumn;
       resultSize++;
      }
  }

这个代码片段应该让你知道如何去做。不过这里有一点需要注意。matchCommands数组已初始化为 4 行 4 列,这很浪费,因为匹配项会少于此如果您需要帮助以提高效率,请告诉我。否则,这是一段工作代码,我认为它可以满足您的需求。

于 2010-01-19T01:10:45.053 回答