Mapping characters to keycodes for international keysets - java
so I built a pi zero keyboard emulator as mentioned here:
https://www.rmedgar.com/blog/using-rpi-zero-as-keyboard-setup-and-device-definition
I make it type text that it reads from a local text-file (everything developed in java - for reasons :) ).
My problem now is that the configured keysets on the various computers my pi zero is attached to differ very much (german, english, french, ...). Depending on the computer this leads to several typing mistakes (e.g., z instead of y).
So I now built some "translation tables" that map characters to the keycodes fitting to the computer. Such a table looks like this:
public scancodes_en_us() {
//We have (Character, (scancode, modifier))
table.put("a",Pair.create("4","0"));
table.put("b",Pair.create("5","0"));
table.put("c",Pair.create("6","0"));
table.put("d",Pair.create("7","0"));
table.put("e",Pair.create("8","0"));
table.put("f",Pair.create("9","0"));
table.put("g",Pair.create("10","0"));
table.put("h",Pair.create("11","0"));
table.put("i",Pair.create("12","0"));
table.put("j",Pair.create("13","0"));
table.put("k",Pair.create("14","0"));
table.put("l",Pair.create("15","0"));
table.put("m",Pair.create("16","0"));
table.put("n",Pair.create("17","0"));
table.put("o",Pair.create("18","0"));
table.put("p",Pair.create("19","0"));
table.put("q",Pair.create("20","0"));
table.put("r",Pair.create("21","0"));
table.put("s",Pair.create("22","0"));
table.put("t",Pair.create("23","0"));
table.put("u",Pair.create("24","0"));
table.put("v",Pair.create("25","0"));
table.put("w",Pair.create("26","0"));
table.put("x",Pair.create("27","0"));
table.put("y",Pair.create("28","0"));
table.put("z",Pair.create("29","0"));
table.put("A",Pair.create("4","2"));
table.put("B",Pair.create("5","2"));
table.put("C",Pair.create("6","2"));
table.put("D",Pair.create("7","2"));
table.put("E",Pair.create("8","2"));
table.put("F",Pair.create("9","2"));
table.put("G",Pair.create("10","2"));
table.put("H",Pair.create("11","2"));
table.put("I",Pair.create("12","2"));
table.put("J",Pair.create("13","2"));
table.put("K",Pair.create("14","2"));
table.put("L",Pair.create("15","2"));
table.put("M",Pair.create("16","2"));
table.put("N",Pair.create("17","2"));
table.put("O",Pair.create("18","2"));
table.put("P",Pair.create("19","2"));
table.put("Q",Pair.create("20","2"));
table.put("R",Pair.create("21","2"));
table.put("S",Pair.create("22","2"));
table.put("V",Pair.create("25","2"));
table.put("W",Pair.create("26","2"));
table.put("X",Pair.create("27","2"));
table.put("Y",Pair.create("28","2"));
table.put("Z",Pair.create("29","2"));
table.put("1",Pair.create("30","0"));
table.put("2",Pair.create("31","0"));
table.put("5",Pair.create("34","0"));
table.put("6",Pair.create("35","0"));
table.put("7",Pair.create("36","0"));
table.put("8",Pair.create("37","0"));
table.put("9",Pair.create("38","0"));
table.put("0",Pair.create("39","0"));
table.put("!",Pair.create("30","2"));
table.put("#",Pair.create("31","2"));
table.put("#",Pair.create("32","2"));
table.put("$",Pair.create("33","2"));
table.put("%",Pair.create("34","2"));
table.put("^",Pair.create("35","2"));
table.put("&",Pair.create("36","2"));
table.put("*",Pair.create("37","2"));
table.put("(",Pair.create("38","2"));
table.put(")",Pair.create("39","2"));
table.put(" ",Pair.create("44","0"));
table.put("-",Pair.create("45","0"));
table.put("=",Pair.create("46","0"));
table.put("[",Pair.create("47","0"));
table.put("]",Pair.create("48","0"));
table.put("\\",Pair.create("49","0"));
table.put(";",Pair.create("51","0"));
table.put("'",Pair.create("52","0"));
table.put("`",Pair.create("53","0"));
table.put(",",Pair.create("54","0"));
table.put(".",Pair.create("55","0"));
table.put("/",Pair.create("56","0"));
table.put("_",Pair.create("45","2"));
table.put("+",Pair.create("46","2"));
table.put("{",Pair.create("47","2"));
table.put("}",Pair.create("48","2"));
table.put("|",Pair.create("49","2"));
table.put(":",Pair.create("51","2"));
table.put("\"",Pair.create("52","2"));
table.put("~",Pair.create("53","2"));
table.put("<",Pair.create("54","2"));
table.put(">",Pair.create("55","2"));
table.put("?",Pair.create("56","2"));
Having such a table for many different keyboard layouts is a pain. Is there some more clever version to map a character to the scancode for a specific keyboard layout?
If not - is there some kind of archive where I can find such a character to scancode mapping for many different keyboard layouts?
Thank you very much
Look at how localization works, they all share the same approach: Create a special version for each localization as a property file, then have an abstract class to load the property based on locale.
You will develop a loader class like this:
public scancodes(Locale locale) {
// load locale property file or download if missing
// read the property and store to the table
ResourceBundle scanCodes = ResourceBundle.getBundle("codes",locale);
}
And your codes_locale looks like:
codes_de.properties
a=4,0
b=5,0
By doing this, you separate the locale specific character with your logic code, and you don't need to bundle all keyboards in side your app. You can download them as needed.
You can access a tutorial here
If I understood what you are trying to do correctly then you don't have to map anything at all, just use a pre-made format (like unicode which works for all languages I know of), just send a char code and translate it to it's matching char.
Example file reader - char interpreter:
JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.showOpenDialog(null);
File textFile = fc.getSelectedFile();
if(textFile.getName().endsWith(".txt")) {
System.out.println(textFile.getAbsolutePath());
FileInputStream input = new FileInputStream(textFile);
BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UNICODE"));
char[] buffer = new char[input.available() / 2 - 1];
System.out.println("Bytes left: " + input.available());
int read = reader.read(buffer);
System.out.println("Read " + read + " characters");
for(int i = 0; i < read; i++) {
System.out.print("The letter is: " + buffer[i]);
System.out.println(", The key code is: " + (int) buffer[i]);
}
}
you can later use the key code to emulate a key press on your computer
For scan-code mappings you can visit following sites:
Keyboard scancodes
Scan Codes Demystified
My solution is to determine the list of keycode on runtime, it'll save you a lot of caffeine and headache
package test;
import java.util.HashMap;
import java.util.Map;
import javax.swing.KeyStroke;
public class Keycode {
/**
* List of chars, can be stored in file
* #return
*/
public String getCharsets() {
return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSVWXYZ12567890!##$%^&*() -=[]\\;'`,./_+{}|:\\~<>?";
}
/**
* Determines the keycode on runtime
* #return
*/
public Map<Character, Integer> getScancode() {
Map<Character, Integer> table = new HashMap<>();
String charsets = this.getCharsets();
for( int index = 0 ; index < charsets.length() ; index++ ) {
Character currentChar = charsets.charAt(index);
KeyStroke keyStroke = KeyStroke.getKeyStroke(currentChar.charValue(), 0);
// only for example i've used Map, but you should populate it by your table
// table.put("a",Pair.create("4","0"));
table.put(currentChar, keyStroke.getKeyCode());
}
return table;
}
public static void main(String[] args) {
System.out.println(new Keycode().getScancode());
}
}
Related
SNMP Listener can not read trap from OIDs that are entries in a table
I have written a SNMP listener in Java using the TNM4J library which uses the SNMP4J library. The listener is able to read received traps, except for traps that appear to be indexed in a table. The listener is listening to traps from an Ericsson object, which means I am using the ERICSSON-ALARM-MIB and the MIB imports it needs. The trap I am receiving is the eriAlarmActiveManagedObject with OID .1.3.6.1.4.1.193.183.4.1.3.5.1.5, but I also tested it locally with the other traps in the table and the same error occurs If one looks at https://mibs.observium.org/mib/ERICSSON-ALARM-MIB/ : All the traps that are from a table like this can not be read by the listener. It gives an index out of bound exception from a extractIndexes method in MibbleIndexExtractor.java in the TNM4J library. #Override public IndexDescriptor[] extractIndexes(String instanceOid) { String oid = symbol.getValue().toString(); String suboid = instanceOid.substring(oid.length() + 1); int[] components = oidToArray(suboid); int offset = 0; IndexDescriptor[] descriptors = new IndexDescriptor[indexes.length]; for (int i = 0; i < indexes.length; i++) { SnmpIndex index = indexes[i]; MibValueSymbol indexSymbol = symbol.getMib().getSymbolByOid(index.getValue().toString()); MibType indexType = ((SnmpObjectType) indexSymbol.getType()).getSyntax(); int length = fixedLength(indexType); boolean implied = length != -1 || index.isImplied(); if (length == -1) { length = variableLength(indexType, components, offset, index.isImplied()); } int[] encoded = new int[length]; System.arraycopy(components, offset, encoded, 0, length); descriptors[i] = new MibbleIndexDescriptor(indexSymbol, encoded, implied); offset += length; } return descriptors; } I have debugged it and this happens because the oid String and instanceOid String are identical which of course causes an exception where the suboid String is being created. However on all other traps it never calls this extractIndexes method, but just works finely and prints out the trap and oid name correctly. Any suggestion on how to fix this issue?
After being in contact with the developer of TNM4J he made some fixes to his library. After that the Ericsson oids was being correctly translated. There was a few missing translations from oids, which was because of the loading order of the MIBs. Re-adjusting these made it work. For anyone interested the troubleshooting process with the developer can view it here: https://github.com/soulwing/tnm4j/issues/9
making an encryption program and im getting a sytnax error but i dont know why
Currently i'm trying to make a basic program that takes an input of any string such as a sentence or a paragraph and it takes each letter and turns it into a 3 character code once i get this working i'm assuming i should just be able to do the reverse and have it take the 3 digit code and turn it back to text, anyway i'm getting an error when i try to compile the program to test it. i have the issue marked below. also once i get the program working i would like to make a gui for it where you put in the input and it shows the out put after you click a button but as i am just starting out that seems a but advanced for me if you know any good tutorials for it please let me know! import java.util.Scanner; import java.util.*; class test { private static Scanner inp; public static void main(String[] args) { Map <Character, String> encryptionMappings = new HashMap<>(); encryptionMappings.put('a',"{qaz}"); encryptionMappings.put('b',"{wsx}"); encryptionMappings.put('c',"{edc}"); encryptionMappings.put('d',"{rfv}"); encryptionMappings.put('e',"{tgb}"); encryptionMappings.put('f',"{yhn}"); encryptionMappings.put('g',"{ujm}"); encryptionMappings.put('h',"{ik,}"); encryptionMappings.put('i',"{ol>}"); encryptionMappings.put('j',"{p;?}"); encryptionMappings.put('k',"{[']}"); encryptionMappings.put('l',"{qwe}"); encryptionMappings.put('m',"{asd}"); encryptionMappings.put('n',"{zxc}"); encryptionMappings.put('o',"{rty}"); encryptionMappings.put('p',"{fgh}"); encryptionMappings.put('q',"{vbn}"); encryptionMappings.put('r',"{yui}"); encryptionMappings.put('s',"{hjk}"); encryptionMappings.put('t',"{nm,}"); encryptionMappings.put('u',"{iop}"); encryptionMappings.put('v',"{qaw}"); encryptionMappings.put('w',"{sxz}"); encryptionMappings.put('x',"{red}"); encryptionMappings.put('y',"{cvf}"); encryptionMappings.put('z',"{ytg}"); encryptionMappings.put('A',"{hnb}"); encryptionMappings.put('B',"{iuj}"); encryptionMappings.put('C',"{kml}"); encryptionMappings.put('D',"{opl}"); encryptionMappings.put('E',"{wom}"); encryptionMappings.put('F',"{wsv}"); encryptionMappings.put('G',"{ths}"); encryptionMappings.put('H',"{imv}"); encryptionMappings.put('I',"{ybf}"); encryptionMappings.put('J',"{cja}"); encryptionMappings.put('K',"{thw}"); encryptionMappings.put('L',"{maz}"); encryptionMappings.put('M',"{pqa}"); encryptionMappings.put('N',"{zwl}"); encryptionMappings.put('O',"{;ld}"); encryptionMappings.put('P',"{'d;}"); encryptionMappings.put('Q',"{;ny}"); encryptionMappings.put('R',"{;ws}"); encryptionMappings.put('S',"{c/.}"); encryptionMappings.put('T',"{%#^}"); encryptionMappings.put('U',"{/mc}"); encryptionMappings.put('V',"{uka}"); encryptionMappings.put('W',"{zby}"); encryptionMappings.put('X',"{&hd}"); encryptionMappings.put('Y',"{&hw}"); encryptionMappings.put('Z',"{^#^}"); encryptionMappings.put('0',"{$g%}"); encryptionMappings.put('1',"{^#%}"); encryptionMappings.put('2',"{142}"); encryptionMappings.put('3',"{243}"); encryptionMappings.put('4',"{089}"); encryptionMappings.put('5',"{756}"); encryptionMappings.put('6',"{423}"); encryptionMappings.put('7',"{312}"); encryptionMappings.put('8',"{145}"); encryptionMappings.put('9',"{187}"); encryptionMappings.put('~',"{)*(}"); encryptionMappings.put('`',"{$#%}"); encryptionMappings.put('!',"{!^#}"); encryptionMappings.put('#',"{#^&}"); encryptionMappings.put('#',"{^#&}"); encryptionMappings.put('$',"{!?*}"); encryptionMappings.put('%',"{^<+}"); encryptionMappings.put('^',"{+$$}"); encryptionMappings.put('&',"{!!*}"); encryptionMappings.put('*',"{((%}"); encryptionMappings.put('(',"{*&^}"); encryptionMappings.put(')',"{$%^}"); encryptionMappings.put('_',"{&#^}"); encryptionMappings.put('-',"{<>?}"); encryptionMappings.put('=',"{:'^}"); encryptionMappings.put('{',"{%%G}"); encryptionMappings.put('}',"{$$$}"); encryptionMappings.put('[',"{***}"); encryptionMappings.put(']',"{:::}"); encryptionMappings.put(':',"{#$%}"); encryptionMappings.put('|',"{?H*}"); encryptionMappings.put(';',"{B&&}"); encryptionMappings.put('"',"{#gs}"); encryptionMappings.put('?',"{^gl}"); encryptionMappings.put('/',"{#gn}"); encryptionMappings.put('<',"{%TG}"); encryptionMappings.put('>',"{5%5}"); encryptionMappings.put(',',"{yty}"); encryptionMappings.put('.',"{ggg}"); inp = new Scanner(System.in); System.out.println("Input Password"); int n = inp.nextInt(); if(n!=234) { System.out.println("Denied Acess"); } else { System.out.print("Password Accepted" + " "); System.out.print("Input Text to encrypt: "); String m = inp.next(); String encryptMe = "He"; StringBuilder builder = new StringBuilder(); The below line is the one that shows a syntax error for "toCharArray" i'm not sure why, I just started learning java so if its something simple that i'm missing i'm sorry, any and all help is apreciated. for (Character c : encryptMe.toCharArray) { builder.append(encryptionMappings.get(c)); } String encrypted = builder.toString(); } }
You are trying to call a method on the object but you are missing the empty () that need to follow toCharArray. Some languages allow you to omit the empty parentheses, but Java is not one of them. You should use: for (Character c : encryptMe.toCharArray()) { builder.append(encryptionMappings.get(c)); } A good IDE (Eclipse, Intellij IDEA, Netbeans, etc.) will help you catch these syntax errors as you learn.
Java: populating Scanner with default value on Scanner.nextLine();
I am writing a java program that runs a loop and keeps asking the user for input. The program then does a bunch of things with the string, and asks for another string and repeats. The issue is that many strings are very similar, so i would like to populate the prompt with the input from the last time in the loop. For instance: If the user enters a value as follows: Enter the SKU Number: APE-6603/A ... Then the next time it asks for an SKU, it will wait till the user presses enter as normal, but be ready with the last value before the user even types anything: Enter the SKU Number: APE-6603/A ... And the user can make simple changes very fast like replace the /A with /B and press enter! If the string that holds the user input is called "lookFor", is there a way to populate the prompt with this value in Java? It would be VERY useful! Thanks!
After discussing this idea with a few people, it seems that what i want is not possible. The way of input is too simple to allow something like this. My only possible solutions involve not running this from my IDE. I can either elect to use my application, or change the application into a GUI based applet. Running from the console will open up the "Press up" option, as suggested by rchirino, and using a GUI would let the value entered sit there for editing later. If anyone is looking to do what i posted above, the answer is "Java cant do it!". Sorry. :)
You might want to try something like this: public String promptandgetWithShowDefault(String prompt, String supplied) { String prmpt = prompt + " (press Enter for \"" + supplied + "\"):"; String tmpch = null; System.out.print(prmpt); tmpch = scanner.nextLine().trim(); if (tmpch == null || tmpch.equals("")) { return supplied; } else { return tmpch; } }
If the goal is to get a simple binar answer from the user like: Would you like to do that? ( y / n ) y then the empty string returned by the user, in the answer from Dmv, will do the trick, except that when the user types "n" or attempts to delete the trailing "y", it won't disappear, so it would then be clearer to write the prompt like: Would you like to do that? ( [ y ] / n ) But when the goal is to get a long string, like the original question or a file path for instance, that the user can edit to correct a typo or not to overwrite previous file .... then you definitely need something else which doesn't seem to be available in Java. Well do it in C then!!! with the help of libreadline... it's probably possible, easier and more portable to do the same trick in Python, but I have no idea how to code in Python. Here is a simple Java MRE to illustrate it: import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; public class Main { public static void main(String[] args) { String path = System.getProperty("user.home") + File.separatorChar + "Documents"; File file = null; do { path = askForString("Enter the filepath to open:", path ); if ( ( path == null) || ( path.isBlank())) break; file = new File( path ); } while ( ! file.exists() ); System.out.println("Openning " + path + "...."); // ...... } public static String askForString( String message, String defaultString) { String response = null; System.out.println( message); // any extra String in cmd[] will be added in readline history String[] cmd = { "/path/to/executable/ask4stringWdefault", defaultString}; try { ProcessBuilder pb = new ProcessBuilder(cmd); // Make sure the subprocess can print on console and capture keyboard events pb.redirectInput(ProcessBuilder.Redirect.INHERIT); pb.redirectOutput(ProcessBuilder.Redirect.INHERIT); Process p = pb.start(); BufferedReader stderrBuffer = new BufferedReader(new InputStreamReader(p.getErrorStream())); int retcode= p.waitFor(); if ( retcode != 0) { System.err.println("The process terminated with error code: " + retcode + "\n" + stderrBuffer.readLine()); return null; } response = stderrBuffer.readLine(); } catch( Exception e) { e.printStackTrace(); } return response; } } To build the executable "ask4stringWdefault" you need first to get the GNU Readline Library utility and compile it, ideally cross-compile for any platform Java supports, to get a static library that you will link while compiling ( or cross-compiling ) the following C script: #include <stdio.h> #include <stdlib.h> #include <readline/readline.h> #include <readline/history.h> const char *defstr; int prefill(const char *txt, int i); int main(int argc, const char * argv[]) { if ( argc < 2) { fprintf(stderr, "You must provide a default value\n"); return -1; } else if ( argc > 2) { // * optional extra values can be passed to populate history * // if ( argc > 255) argc = 255; for ( unsigned char i=0; i < argc; i++) { add_history(argv[i]); } } defstr = argv[1]; char *cbuffer; rl_startup_hook = prefill; if ((cbuffer = readline(NULL)) == NULL) /* if the user sends EOF, readline will return NULL */ return 1; fprintf( stderr, "%s\n", cbuffer); free(cbuffer); return 0; } int prefill(const char *t, int i) { rl_insert_text(defstr); return 0; } The result is printed on stderr as it is the only stream that Java can keep track of, stdout and stdin being under the control of the executable subprocess itself. It works fine on a Mac with arm64 architecture, using Eclipse you can't actually edit the default provided, any character typed at the prompt will be append to default string, but just hitting return will send unchanged default value back, which can be enough for basic testing.
I think I understand what you want to do, but it's rather simple. If your program is a console application (command-line), which I'll assume, then you just need to press the UP key to populate the prompt with the last typed characters. If you're working with GUI elements then you can check the API documentation for the particular class of object you're using and check out it's fields. Hope this helps!
Checking domain name age through Java
I am making a simple phishing scanner tool for a university project. One of my detection methods includes checking if the DNS within the email are valid, and I also want to check their age. This is example code of how I check if they are existing: import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; import java.util.Hashtable; public class DNSExample { static int doLookup( String hostName ) throws NamingException { Hashtable env = new Hashtable(); env.put("java.naming.factory.initial", "com.sun.jndi.dns.DnsContextFactory"); DirContext ictx = new InitialDirContext( env ); Attributes attrs = ictx.getAttributes( hostName, new String[] { "MX" }); Attribute attr = attrs.get( "MX" ); if( attr == null ) return( 0 ); return( attr.size() ); } public static void main( String args[] ) { String [] array = {"google.com","dsad33114sssaxzx.com"} ; for( int i = 0; i < array.length; i++ ) { try { System.out.println( array[i] + " has " + doLookup( array[i] ) + " mail servers" ); } catch( Exception e ) { System.out.println(array[i] + " : " + e.getMessage()); } } } } How would I need to modify the above code to include a check of age for servers that exist?
I think you've chosen a problem that cannot be solved in the general case ... using current generation internet standards: The information you need cannot be obtained from DNS itself. In some cases information about DNS registrations can be obtained from WHOIS. However, the information returned by WHOIS servers is not standardised: There is no standard information model. There is no standard format. There are no guarantees as to the accuracy of the information. It is not even clear if "age of server" is going to be available. (For instance, the closest that APNIC's WHOIS provides to that is the last modification timestamp for the DNS record. And that is NOT a good proxy for server age.) There is a set of RFC's that define something called CRISP, but as far as I can make out the purpose of that standard is for registrar to registrar exchange of information. (I couldn't find any public-facing services based on CRISP.) There is also an IETF working group called WEIRDS which I think is intended to define a web-enabled replacement for WHOIS. (Don't confuse WEIRDS with the IETF WEIRD WG!) But that was formed very recently, and it is too soon to make any predictions of the outcome. (Or how long it will take for the NICs to implement any specs that come out of the WG.) Summary: your chances of implementing something in this space that really works are currently low. Probably the best you can hope to achieve is something based on screen-scraping one or two WHOIS services. This might change in a few years, but that is of no help for your current project.
It seems based on your description and comments above you are trying to gather whois information. download APIs from http://commons.apache.org/proper/commons-net/ change the nameToQuery below and run it. public class WhoisIt { public static final String WHOIS_SERVER = "whois.internic.net"; public static final int WHOIS_PORT = 43; public static void main(String[] args) throws Exception { String nameToQuery = "avajava.com"; WhoisClient whoisClient = new WhoisClient(); whoisClient.connect(WHOIS_SERVER, WHOIS_PORT); String results = whoisClient.query(nameToQuery); System.out.println(results); } } good luck
Batch file renaming – inserting text from a list (in Python or Java)
I'm finishing a business card production flow (excel > xml > indesign > single page pdfs) and I would like to insert the employees' names in the filenames. What I have now: BusinessCard_01_Blue.pdf BusinessCard_02_Blue.pdf BusinessCard_03_Blue.pdf (they are gonna go up to the hundreds) What I need (I can manipulate the name list with regex easily): BusinessCard_01_CarlosJorgeSantos_Blue.pdf BusinessCard_02_TaniaMartins_Blue.pdf BusinessCard_03_MarciaLima_Blue.pdf I'm a Java and Python toddler. I've read the related questions, tried this in Automator (Mac) and Name Mangler, but couldn't get it to work. Thanks in advance, Gus
Granted you have a map where to look at the right name you could do something like this in Java: List<Files> originalFiles = ... for( File f : originalFiles ) { f.renameTo( new File( getNameFor( f ) ) ); } And define the getNameFor to something like: public String getNameFor( File f ) { Map<String,String> namesMap = ... return namesMap.get( f.getName() ); } In the map you'll have the associations: BusinessCard_01_Blue.pdf => BusinessCard_01_CarlosJorgeSantos_Blue.pdf Does it make sense?
In Python (tested): #!/usr/bin/python import sys, os, shutil, re try: pdfpath = sys.argv[1] except IndexError: pdfpath = os.curdir employees = {1:'Bob', 2:'Joe', 3:'Sara'} # emp_id:'name' files = [f for f in os.listdir(pdfpath) if re.match("BusinessCard_[0-9]+_Blue.pdf", f)] idnumbers = [int(re.search("[0-9]+", f).group(0)) for f in files] filenamemap = zip(files, [employees[i] for i in idnumbers]) newfiles = [re.sub('Blue.pdf', e + '_Blue.pdf', f) for f, e in filenamemap] for old, new in zip(files, newfiles): shutil.move(os.path.join(pdfpath, old), os.path.join(pdfpath, new)) EDIT: This now alters only those files that have not yet been altered. Let me know if you want something that will build the the employees dictionary automatically.
If you have a list of names in the same order the files are produced, in Python it goes like this untested fragment: #!/usr/bin/python import os f = open('list.txt', 'r') for n, name in enumerate(f): original_name = 'BusinessCard_%02d_Blue.pdf' % (n + 1) new_name = 'BusinessCard_%02d_%s_Blue.pdf' % ( n, ''.join(name.title().split())) if os.path.isfile(original_name): print "Renaming %s to %s" % (original_name, new_name), os.rename(original_name, new_name) print "OK!" else: print "File %s not found." % original_name
Python: Assuming you have implemented the naming logic already: for f in os.listdir(<directory>): try: os.rename(f, new_name(f.name)) except OSError: # fail You will, of course, need to write a function new_name which takes the string "BusinessCard_01_Blue.pdf" and returns the string "BusinessCard_01_CarlosJorgeSantos_Blue.pdf".