tokenizer générique Java Shell
-
21-09-2019 - |
Question
Mon Java est extrêmement rouillé et je suis coincé essayer de faire une interface utilisateur qui simplifie l'exécution des scripts shell ou des fichiers batch selon que ce soit Linus ou Win32 respectivement. Les fichiers ont la convention de nommage suivante.
module-verb-object-etc [args-list]
mysql-connect-grid
mysql-connect-rds
mysql-dump-grid
mysql-dump-grid-se314
finalement, je voudrais qu'il analyser sans ambiguïté que je puisse:
- tokenize les commandes (par exemple, délimitées par des « - ») et raccourcissez en termes simplifiés soemthing comme la fenêtre de commande de foxpro ou IOS cisco (par exemple, « mon co gr » exécute « mysql-connect-grid » dans unix et * .cmd dans win32)
- et aussi dans le style de l'IOS permettent à l'utilisateur d'entrer des commandes abrégées afin qu'ils puissent saisir un point d'interrogation (?) Et il leur donnera une indication quant aux options de commande unique, restant (ou suivant) (par exemple " mon? » MySQL retourne et « renvoie mes? » Se connecter ou décharge). Les valeurs othr de retour seraient « ambigus » ou « inconnu » pour les commandes qui ne sont pas uniques ou ne pouvaient pas être apparié. Il peut sembler trivial, mais il y a plusieurs centaines de commandes dans chaque dossier et mes utilisateurs ne veulent pas penser ...
J'ai écrit une fonction pour tirer la liste des fichiers à partir d'un répertoire et retun un tableau de fileanmes. Puis je convertir en un réseau bidimensionnel 2 en utilisant la méthode ci-dessous qui renvoie une grille de taille de dynamicly de commandes possibles.
/**********************************************************************************
* 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;
}
renvoie une matrice 2-D (ci-dessous), de sorte que grid[Row-N][Col-0]
est une allumette. Je voudrais tirer que des valeurs distinctes où row[0]
est un match de joker pour cmdToken[0] && row[1]
est « comme » cmdToken[1]
pour que mes utilisateurs peuvent rassembler une commande jusqu'à ce que "my du gr ?"
retourne "ENTER, [se314]"
- si cela fait sens ...
String[][] makeGrid:
mysql dump grid se314
mysql connect grid
mysql dump grid
mysql connect rds
Mon défi: Je ne peux pas sembler obtenir ma tête autour de ma fonction de matcher en java. Si c'était SQL ce serait quelque chose comme:
"SELECT DISTINCT col2 FROM cmd_Grid
WHERE col1 LIKE 'cmdToken1%' "
ou mieux encore: la mise en récursivement un depthmark int pour chaque colonne consécutive
`SELECT DISTINCT col+str(depthmark+1) FROM cmd_Grid
WHERE col+str(depthmark) LIKE 'cmdMatchedTokens%' "
jusqu'à ce que vous avez une correspondance exacte.
J'ai trouvé un paquet appelé joSQL que j'ai essayé en désespoir de cause, mais je ne peux pas l'air de le faire fonctionner dans java6. Quoi qu'il en soit: j'espérais aussi une solution pure java pour que tout pourrait être contenu dans une seule classe ...
en utilisant peut-être scanner ou quelque chose pour analyser mon tableau des valeurs uniques pour multidimentionnelle ... Je sais que je suis sans doute ce qui en fait beaucoup plus complexe qu'il doit être.
un petit coup de pouce dans la bonne direction serait appréciée.
TIA
La solution
Une solution exhaustive pourrait être à contruct HashMap de sorte que la clé est une commande courte possible, comme mon co gr » et la valeur correspondante est « mysql-connect-grid ». Donc, il y aurait des valeurs dans la carte de hachage qui aura « mysql-connexion réseau » comme valeur.
Mais ceci est une solution réalisable que s'il y a un nombre fini de clés possibles. Si ce n'est pas le cas, vous pouvez utiliser les fonctions intégrées dans les méthodes d'analyse de chaînes.
Par exemple:
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++;
}
}
Cet extrait de code devrait vous donner une idée de la façon de s'y prendre. Il y a une chose à noter ici cependant. matchingCommands array a été initialisé aux 4 lignes et 4 colonnes qui est inutile parce que les matches seront moins que cela. Laissez-moi savoir si vous avez besoin d'aide pour faire de ce plus efficace. Dans le cas contraire, c'est un morceau de travail de code qui je pense ne ce que vous voulez.
Autres conseils
Vous pouvez également regarder dans certaines structures de données plus avancées comme un ArrayList au lieu d'un tableau et en utilisant la StringTokenizer pour générer chaque commande partie à la volée.
Ce sera quelque chose comme ceci:
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);
Ceci assurez-vous que votre programme peut se développer de façon dynamique et il n'y a pas de gaspillage de la mémoire à cause d'objets nuls non plus.
en ce moment je en train de jouer autour de chaque analyse syntaxique chaîne_cmd (requête) pour délimiteurs espace blanc et tokenizing le tableau. Quelque chose comme:
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+"...");
}
}
}
mais je devenais NPE avec les longueurs inégales de ligne.
J'aime votre idée d'aplatir les colonnes.
Je pense que je dois encore supprimer les doublons ... non?