Pergunta

Meu Java está extremamente enferrujado e estou preso tentando fazer uma interface de usuário que simplifica a execução de scripts de shell ou arquivos em lote, dependendo se é Linus ou Win32, respectivamente. Os arquivos têm a seguinte convenção de nomeação.

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

Em última análise, eu gostaria que ele analisasse termos inequívocos para que eu possa:

  1. Tokenize os comandos (por exemplo, delimitado por "-") e encurte-os em termos simplificados como a janela de comando da Foxpro ou o iOS da Cisco (por exemplo, "meu CO GR" executa "MySQL-Connect-Grid" no Unix e *.cmd em Win32)
  2. E também no estilo do iOS permite que o usuário entre nos comandos abreviados para que eles possam digitar um ponto de interrogação (?) E isso lhes dará uma dica sobre as opções de comando restantes (ou próximas) exclusivas (por exemplo, "My?" Retorna o MySQL & "My?" Retorna Connect ou Dump). Os valores de retorno de outros seriam "ambíguos" ou "desconhecidos" para comandos que não são únicos ou não poderiam ser correspondidos. Pode parecer trivial, mas há muitas centenas de comandos em cada pasta e meus usuários não querem pensar ...

Eu escrevi uma função para puxar a lista de arquivos de um diretório e retun uma matriz de FileanMes. Em seguida, converti isso em uma matriz bidimensional usando o método abaixo, que retorna uma grade de tamanho dinâmico de comandos em potencial.

    /**********************************************************************************
     *  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;
      }

Isso retorna uma matriz 2D (abaixo), então grid[Row-N][Col-0] é uma partida. Eu gostaria de puxar apenas valores distintos onde row[0] é uma partida curinga para cmdToken[0] && row[1] é como" cmdToken[1] para que meus usuários possam juntar um comando até "my du gr ?" retorna "ENTER, [se314]" - Se isso faz sentido ...

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

Meu desafio: pareço não conseguir entender minha função Matchers em Java. Se fosse SQL, seria algo como:

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

Ou melhor ainda: definir recursivamente uma marca de profundidade para cada coluna consecutiva

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

até você ter uma correspondência exata.

Encontrei um pacote chamado Josql que tentei por desespero, mas não consigo fazer com que funcione no Java6. De qualquer forma: eu também esperava uma solução pura de java para que tudo pudesse estar contido em uma única classe ...

Talvez usando o scanner ou algo para analisar minha matriz multidimensional para valores únicos ... eu sei que provavelmente estou tornando -o muito mais complexo do que precisa.

Uma cutucada suave na direção certa seria apreciada.

Tia

Foi útil?

Solução

Uma solução exaustiva pode ser a conclusão de um hashmap para que a chave seja um possível comando curto como 'meu CO GR "e o valor correspondente é" MySQL-Connect-Grid ". Portanto, haveria valores no mapa de hash que terão" MySQL-Connect-grid "como o valor.

Mas esta é uma solução viável apenas se houver um número finito de teclas possíveis. Se não for esse o caso, você pode usar os métodos de análise de string embutidos.

Por exemplo:

    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++;
      }
  }

Este snippet de código deve dar uma idéia de como fazer isso. Há uma coisa a ser observada aqui. o MatchingCommands A matriz foi inicializada nas 4 linhas e 4 colunas, o que é um desperdício porque as correspondências serão menores que isso. Deixe -me saber se precisar de ajuda para tornar isso mais eficiente. Caso contrário, este é um pedaço de código funcional que eu acho que faz o que você deseja.

Outras dicas

Você também pode usar algumas estruturas de dados mais avançadas, como uma lista de Array em vez de uma matriz e usar o StringTokenizer para gerar cada peça de comando em tempo real.

Será algo assim:

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);

Isso garantiria que seu programa possa crescer dinamicamente e não há desperdício de memória por causa de objetos nulos.

No momento, eu estava brincando com a análise de cada cmdstring (consulta) para delimitadores de espaço em branco e tokenizando a matriz. Algo como:

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

Mas eu estava recebendo NPEs com os comprimentos irregulares da linha.

E eu gosto da sua ideia de achatar as colunas.

Eu acho que ainda teria que remover duplicatas ... não?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top