Java Shell подстановочный токенайзер - PullRequest
0 голосов
/ 19 января 2010

Моя Java чрезвычайно ржавая, и я застрял, пытаясь создать пользовательский интерфейс, который упрощает выполнение сценариев оболочки или пакетных файлов в зависимости от того, будет ли это Linus или Win32 соответственно. Файлы имеют следующие правила именования.

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

в конечном итоге я бы хотел, чтобы он разбирал недвусмысленные термины, чтобы я мог:

  1. токенизируйте команды (например, разделенные символом "-") и сократите их до упрощенных терминов, таких как окно команд foxpro или IOS cisco (например, "my co gr" выполняет "mysql-connect-grid" в unix и * .cmd в win32)
  2. , а также в стиле IOS позволяют пользователю вводить сокращенные команды, чтобы они могли вводить знак вопроса (?), И это даст им подсказку об уникальных оставшихся (или следующих) параметрах команды (например, " my? "возвращает mysql &" my? "возвращает connect или dump). Другие возвращаемые значения будут «неоднозначными» или «неизвестными» для команд, которые не являются уникальными или не могут быть сопоставлены. Это может показаться тривиальным, но в каждой папке много сотен команд, и мои пользователи не хотят думать ...

Я написал функцию для извлечения списка файлов из каталога и повторного запуска массива fileanmes. Затем я преобразую это в двухмерный массив, используя метод, приведенный ниже, который возвращает динамически измеренную сетку потенциальных команд.

    /**********************************************************************************
     *  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] - это "похоже" cmdToken[1], так что мои пользователи могут собрать команду, пока "my du gr ?" не вернет "ENTER, [se314]" - если это имеет смысл ...

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

My Challenge: Кажется, я не могу разобраться с функцией соответствия в Java. Если бы это был SQL, это было бы что-то вроде:

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

или даже лучше: рекурсивная установка глубины int для каждого последовательного столбца

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

пока у вас нет точного соответствия.

Я нашел пакет с именем joSQL, который я отчаянно попробовал, но не могу заставить его работать в Java6. В любом случае: я также надеялся на чистое решение Java, чтобы все могло содержаться в одном классе ...

Может быть, с помощью сканера или чего-то еще для анализа моего многомерного массива на предмет уникальных значений ... Я знаю, что, вероятно, делаю его более сложным, чем нужно.

будет приветствоваться легкое толчок в правильном направлении.

ТИА

Ответы [ 3 ]

1 голос
/ 19 января 2010

Можно также использовать некоторые более сложные структуры данных, такие как 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);

Это обеспечит динамический рост вашей программы и отсутствие потерь памяти из-за нулевых объектов.

0 голосов
/ 19 января 2010

сейчас я возился с разбором каждого 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 с неравной длиной строки.

И мне нравится твоя идея расплющить колонны.

Думаю, мне все равно придется удалять дубликаты ... нет?

0 голосов
/ 19 января 2010

Одним из исчерпывающих решений может быть создание 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++;
      }
  }

Этот фрагмент кода должен дать вам представление о том, как это сделать. Здесь следует отметить одну вещь. Массив MatchingCommands был инициализирован в 4 строки и 4 столбца, что бесполезно, поскольку совпадения будут меньше, чем это. Дайте мне знать, если вам нужна помощь, чтобы сделать это более эффективным. В противном случае это рабочий кусок кода, который, я думаю, делает то, что вы хотите.

...