Regex to fetch only Key Value pairs and omit some charaters - java

I have this data
ReferenceDataLocation = as
##############################################################################
#
# LicenseKey
# Address Doctor License
#
##############################################################################
LicenseKey = al
which I'd like to capture only key value pairs eg: ReferenceDataLocation = as and LicenseKey = al
I wrote (?xms)(^[\w]+.*?)(?=^[\w]+|\z) regex which is perfect except the fact that it also captures ##### part, which is not key value pair.
Please help me modify the same regex (?xms)(^[\w]+.*?)(?=^[\w]+|\z) to only get ReferenceDataLocation = as and LicenseKey = al
Note: Here you can try out
Update
I tried (?xms)(^[\w]+.*?)(?=^[\w^#]+|\z) it works in the site but gives me an error in java
Exception in thread "main" java.util.regex.PatternSyntaxException: Unclosed character class near index 31
(?xms)(^[\w]+.*?)(?=^[\w^#]+|\Z)
^
Updat Regex that works for me
(?xms)(^[\w]+.*?)(?=^[\w^\s]+|\z)

You can't do that with a simple regex-match. You can't account for occurrences like these:
# some words here LicenseKey = al
The regex engine cannot look behind from LicenseKey to the end of the line. This is not supported in Java's regex engine (unbounded look-behinds).
But what you posted looks like it's just a properties file. Try this:
import java.io.FileInputStream;
import java.util.Properties;
public class Main {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("test.properties"));
System.out.println(properties.getProperty("ReferenceDataLocation"));
System.out.println(properties.getProperty("LicenseKey"));
System.out.println(properties.getProperty("foo"));
}
}
which will print:
as
al
null
Note that your input file needn't be called test.properties, you can give it any name you like.
And if you don't know the keys up front, you can simply iterate over all entries in your properties file like this:
for(Map.Entry<Object, Object> entry : properties.entrySet()) {
System.out.println(entry.getKey() + " :: " + entry.getValue());
}
which prints:
LicenseKey :: al
ReferenceDataLocation :: as
And there's also Properties#stringPropertyNames() which returns a Set<String> that represents all keys in the properties file (see the API docs for more info).
See:
Tutorial: http://download.oracle.com/javase/tutorial/essential/environment/properties.html
API docs: http://download.oracle.com/javase/7/docs/api/java/util/Properties.html

Related

Common configuration 2 - commented properties

i'm developing a java desktop application to use as a tool to manipulate properties files.
So my application need to to load a TXT file containing several keys (or properties), and be able to changes there values.
I use Apache commons configurations 2 project to do this work.
Everything was going well until a face this situation..
there is a txt file contating several properties but, one properties (or key) has a # before his name (look at config.txt file below), so apache commons do not recognize this propertie.
When i set a value to this propertie (look at last two lines on main method), apache commons configurator creates a new line on config.txt
This is not good to me, because i need to preserve the original config.txt format, so if i need to set a value to fileDb propertie, my expected behavior is to remove the # from fileDb name and do not create a new fileDb propertie on config.txt.
the program that uses this configuration file (config.txt) understands that if the property is commented (if it has "#" in its name), it means that it should not be used, but if it is uncommented (without "#" in the name) means that it should be used and that its value should be read.
So what can i do to add or remove "#" from the propertie name using common configuration? if is not possible to do it with commons configurator, how to do it?
On the ConfigTest class i show how the problem ocours.
Before run the code, the file config.txt has a commented propertie named fileDB
#fileDb = C:/test/test.db
the maind method try to change the filedb value to "C://aa//bb//cc"
but after the executions end wil appears a new propetie with the same name "fileDb" but uncomented (without "#"). At the end, config.txt wil have two fileDb propertie, one with "#" and other without "#"
#fileDb = C:/test/test.db
fileDb = C://aa//bb//cc
My expectd behavior after the code execution is to has only one fileDb propetie
fileDb = C://aa//bb//cc
After be able to uncoment this propertie i expect to be able to comment again if necessery (if user wish to do it on my app).
ConfigTest class
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.FileBasedBuilderParameters;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import java.io.File;
public class ConfigTest {
private Configuration localConfiguration;
private FileBasedConfigurationBuilder<FileBasedConfiguration> fileBuilder;
private ConfigTest() throws ConfigurationException {
this.loadPropertiesFile();
}
private void loadPropertiesFile() throws ConfigurationException {
File file = new File("config.txt");
FileBasedBuilderParameters fb = new Parameters().fileBased();
fb.setFile(file);
fileBuilder = new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class);
fileBuilder.configure(fb);
localConfiguration = fileBuilder.getConfiguration();
}
public boolean saveModifications(){
try {
fileBuilder.save();
return true;
} catch (ConfigurationException e) {
e.printStackTrace();
return false;
}
}
public void setProperty(String key, String value){
localConfiguration.setProperty(key,value);
}
public static void main(String[] args) throws ConfigurationException {
ConfigTest test = new ConfigTest();
//change outputOnSSD propertie value to false
test.setProperty("outputOnSSD", "false");
//here when i set a new value to fileDb propertie, a new line on config.txt with a new fileDb propertie name is created
//the question is: how to remove # from fileDb propetie name on config.txt to commons config recognize it as a existent propertie?
test.setProperty("fileDb", "C://aa//bb//cc");
test.saveModifications();
}
}
File "config.txt" used by ConfigTest class to change his value
########################################################################
# Local environment configuration
########################################################################
# Defines program localization/language
locale = pt-BR
# Temporary directory for processing: "default" uses the system temporary folder.
indexTemp = /home/downloads
# Enable if is on a SSD disk.
indexTempOnSSD = true
# Enable if output/case folder is on SSD. If enabled, index is created directly in case folder,
outputOnSSD = false
# Number of processing threads/workers: "default" uses the number of CPU logical cores.
numThreads = 14
# Full path for hash index database.
#fileDb = C:/test/test.db

Is there a way to use place holders in Apache PropertiesConfiguration

I have the following configuration setup using Apache Configuration:
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
Configuration config = new PropertiesConfiguration("config.properties");
I want to know if there is some way to use place holders in the properties file? For example, I want to have this:
some.message = You got a message: {0}
And be able to pass in the value for the {0} place holder. Typically, you can usually do something like config.getString("some.message", String[] of values) but don't see anything like that.
As far as I know, Configuration class doesn't provide any formatters. So, for your task
You can use MessageFormat as it was suggested by Bilguun. Please
note, that format method is static.
You can use String.format function.
Examples is bellow:
config.properties
enter some.message.printf=%1$s\, you've got a message from %2$s \n
some.message.point.numbers =Hey {0}\, you got message: {1}!
Example class
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import java.text.MessageFormat;
public class ConfigurationTest {
public static void main(String[] args) throws ConfigurationException {
Configuration config = new PropertiesConfiguration("config.properties");
String stringFormat = String.format(config.getString("some.message.printf"), "Thomas", "Andrew");
// 1 String format
System.out.println(stringFormat);
// 2 Message Format
System.out.println(MessageFormat.format(config.getString("some.message.point.numbers"), "Thomas", "Hello"));
}
}
I believe you could get property value with placeholder from a property file and then use MessageFormat to formatting the message to what you desired. Let's say you got following property in your property file:
some.message = "Hey {0}, you got message: {1}!"
So that you get and format this property like:
message will be "Hey {0}, you got message: {1}!"
String message = config.getString("some.message");
MessageFormat mf = new MessageFormat("");
//it will print: "Hey Thomas, you got message: 1"
System.out.println(mf.format(message, "Thomas", 1));
Also, if you could use system variables or environmental variables if it is not changed on the fly

antlr return values as key-value

I want to parse the sentence "i am looking for a java developer from india".
The output i need is language=java and place=india
I created a grammar file as follows.
grammar Job;
eval returns [String value]
: output=jobExp {System.out.println($output.text); $value = $output.text;}
;
jobExp returns [String value]
: ind=indro whitespace var1=language ' developer from ' var2=place
{
System.out.println($var1.text);
System.out.println($var2.text);
$value = $var1.text+$var2.text; }
;
indro
:
'i am looking for a'
|
'i am searching for a'
;
language :
'java' | 'python' | 'cpp'
;
place :
'india' | 'america' | 'africa'
;
whitespace :
(' '|'\t')+
;
inside jobExp i am getting the values for place and language. And I am just returning only those two variables. But in eval i am getting the whole sentence(i am looking for a java developer from india). What should i need to get the exact matching output in eval ? Is it possible to get the output as json or hashMap in antlr?
My java class for testing the grammar as follows:
import org.antlr.runtime.*;
public class JobTest {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("i am looking for a java developer from india" );
JobLexer lexer = new JobLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
JobParser parser = new JobParser(tokens);
System.out.println(parser.eval()); // print the value
}
}
You can have a #header block in your grammar to add it to the generated parser file.
grammar Job;
#header {
import java.util.HashMap;
}
You can further on your grammar file use the HashMap class just as you're using String.
There's also the #members block to define private fields of the parser. You can check an example using both blocks to define an expression evaluator in this tutorial.

How do you escape colon (:) in Properties file?

I am using a properties file to store my application's configuration values.
In one of the instances, I have to store a value as
xxx:yyy:zzz. When I do that, the colon is escaped with a back slash\ resulting in the value showing as xxx\:yyy\:zzz in the properties file.
I am aware that the colon : is a standard delimiter of the Properties Java class. However I still need to save the value without the back slash \.
Any suggestions on how to handle this?
Put the properties into the Properties object and save it using a store(...) method. The method will perform any escaping required. The Java documentation says:
"... For the key, all space characters are written with a preceding \ character. For the element, leading space characters, but not embedded or trailing space characters, are written with a preceding \ character. The key and element characters #, !, =, and : are written with a preceding backslash to ensure that they are properly loaded."
You only need to manually escape characters if you are creating / writing the file by hand.
Conversely, if you want the file to contain unescaped colon characters, you are out of luck. Such a file is malformed and probably won't load properly using the Properties.load(...) methods. If you go down this route, you'll need to implement your own custom load and/or store methods.
I came across the same issue. Forward slashes / also get escaped by the store() method in Properties.
I solved this issue by creating my own CustomProperties class (extending java.util.Properties) and commenting out the call to saveConvert() in the customStore0() method.
Here is my CustomProperties class:
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
public class CustomProperties extends Properties {
private static final long serialVersionUID = 1L;
#Override
public void store(OutputStream out, String comments) throws IOException {
customStore0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
comments, true);
}
//Override to stop '/' or ':' chars from being replaced by not called
//saveConvert(key, true, escUnicode)
private void customStore0(BufferedWriter bw, String comments, boolean escUnicode)
throws IOException {
bw.write("#" + new Date().toString());
bw.newLine();
synchronized (this) {
for (Enumeration e = keys(); e.hasMoreElements();) {
String key = (String) e.nextElement();
String val = (String) get(key);
// Commented out to stop '/' or ':' chars being replaced
//key = saveConvert(key, true, escUnicode);
//val = saveConvert(val, false, escUnicode);
bw.write(key + "=" + val);
bw.newLine();
}
}
bw.flush();
}
}
We hit this question a couple of days ago. We were manipulating existing properties files with URLs as values.
It's risky but if your property values are less than 40 characters then you can use the "list" method instead of "store":
http://docs.oracle.com/javase/6/docs/api/java/util/Properties.html#list(java.io.PrintWriter)
We had a quick look at the JDK code and hacked out a custom implementation of store that works for our purposes:
public void store(Properties props, String propertyFilePath) throws FileNotFoundException {
PrintWriter pw = new PrintWriter(propertyFilePath);
for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
String key = (String) e.nextElement();
pw.println(key + "=" + props.getProperty(key));
}
pw.close();
}
If you use the xml variant of the properties file (using loadFromXML and storeToXML) this shouldn't be a problem.
Try using unicode.
The unicode for a colon is\u003A
Additionally the unicode for a space is: \u0020
For a list of basic Latin characters see: https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
For example:
ProperName\u003A\NameContinues=Some property value
Will expect a property with a key:
ProperName:NameContinues
And will have a value of:
Some property value
For me it worked by using \ before special character,
e.g,
Before: VCS\u003aIC\u0020Server\u003a=Migration
After: VCS\:IC\ Server\:=Migration
: is escaped with \: and (space) with \ (\ followed by <Space>).
For more info : https://en.wikipedia.org/wiki/.properties
For people like me that get here for this when using Spring Boot configuration properties files: You need to enclose in [..]:
E.g.:
my.test\:key=value
is not enough, you need this in your application.properties for example:
my.[test\:key]=value
See also SpringBoot2 ConfigurationProperties removes colon from yaml keys
Its simple,
just use Apostrophe ' ' over there
E.g.:
Instead of this(case 1)
File file= new File("f:\\properties\\gog\\esave\\apple");
prop.setProperty("basedir",file.toString());
Use this(case 2)
File file= new File("f':'\\properties\\gog\\esave\\apple");
prop.setProperty("basedir",file.toString());
Output will be
Case 1: basedir = f\:\\properties\\gog\\esave\\apple
Case 2: basedir = f:\\properties\\gog\\esave\\apple
I hope this will help you

Java properties containing dollar delimited variables

I'm storing my app settings in properties file that I use in Ant and in the Java app. Maybe it's not good pratice, but I find it very handy to avoid duplications. The file contains variables such as:
usefulstuff.dir = ${user.home}/usefulstuff
So that other people can run the program on *nix systems, provided that they have the usefulstuff folder in their home directory.
Now, the fascinating thing is that this properties file works fine in Ant (the variable gets resolved to /home/username), while when I load the same file directly in the Java app, I get a string containing ${user.home}/usefulstuff, which is not very useful indeed.
I load the props with this code in Ant:
<loadproperties srcFile="myProps.properties"/>
And in the Java app:
FileInputStream ins = new FileInputStream(propFilePath);
myProps.load(ins);
ins.close();
Am I missing anything? Maybe is there a better way to load properties in a Java app than load()?
I don't think it's particularly "fascinating" that this works in Ant - Ant is deliberately written to do so:
Properties are key-value-pairs where Apache Ant tries to expand ${key} to value at runtime.
and
Ant provides access to all system properties as if they had been defined using a <property> task. For example, ${os.name} expands to the name of the operating system.
If you want the same behaviour, you'll need to implement the same sort of logic. It's possible that you could use the classes from Ant directly, if they do what you want - and if you're happy to ship the relevant binaries (and abide by the licence).
Otherwise, you might want to use a regular expression to find all the matches - or (probably simpler) iterate over all of the system properties and do a simple replacement on them.
As Jon said, it should be straighforward to write the property handling yourself. For eg:
import java.util.*;
public class PropertiesTest
{
public static void main(String[] args)
{
Properties props = new Properties();
props.setProperty("foo", "foo/${os.name}/baz/${os.version}");
props.setProperty("bar", "bar/${user.country}/baz/${user.country}");
System.out.println("BEFORE:");
printProperties(props);
resolveSystemProperties(props);
System.out.println("\n\nAFTER:");
printProperties(props);
}
static void resolveSystemProperties(Properties props)
{
Map<String, String> sysProps = readSystemProperties();
Set<String> sysPropRefs = sysProps.keySet();
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
String value = props.getProperty(name);
for (String ref : sysPropRefs)
{
if (value.contains(ref))
{
value = value.replace(ref, sysProps.get(ref));
}
}
props.setProperty(name, value);
}
}
static Map<String, String> readSystemProperties()
{
Properties props = System.getProperties();
Map<String, String> propsMap =
new HashMap<String, String>(props.size());
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
propsMap.put("${" + name + "}", props.getProperty(name));
}
return propsMap;
}
static void printProperties(Properties props)
{
Enumeration names = props.propertyNames();
while (names.hasMoreElements())
{
String name = (String) names.nextElement();
String value = props.getProperty(name);
System.out.println(name + " => " + value);
}
}
}

Categories