Java - RegEx pattern that consists of LDAP attributes - java

Is there a way to use LDAP attributes stored in Strings as the RegEx pattern?
I am thinking something like this:
PASSWORD_WITH_LDAP_ATTRIBUTE = Pattern.compile(userid + "|" + ssn + "|" + bdate + "|" + empNo + "|" + telNo);
I already tried this one out. In any string that I input, the regex always finds a match even though its not a clear match.
Is this possible or am I venturing to the impossible?
Here is the whole method:
private static Pattern PASSWORD_WITH_LDAP_ATTRIBUTE = null;
private boolean checkForLdapAttributes(final String newPassword) throws LDAPException{
LoggingEnt loggingEnt = new LoggingEnt();
String userid = loggingEnt.getUseridCode();
String ssn = loggingEnt.getSocialSecurityNumber();
String bdate = loggingEnt.getBirthDate();
String empNo = loggingEnt.getEmployeeNumber();
String telNo = loggingEnt.getTelephoneNumber();
PASSWORD_WITH_LDAP_ATTRIBUTE = Pattern.compile(userid + "|" + ssn + "|" + bdate + "|" + empNo + "|" + telNo);
matcher = PASSWORD_WITH_LDAP_ATTRIBUTE.matcher(newPassword);
if(PASSWORD_WITH_LDAP_ATTRIBUTE.matcher(newPassword).find()){
isPasswordAccepted = false;
loggingEnt.setMsg1("You cannot use any of your Username, Social Security No., Birthdate, Employee No., and Telephone No. as password.");
throw new LDAPException("Invalid password combination for " + userid, LDAPException.INVALID_CREDENTIALS);
} else {
loggingEnt.setMsg1("Password accepted.");
isPasswordAccepted = true;
}
return matcher.matches();
}

You're doing this wrong. You're not supposed to match the password attribute yourself. You are supposed to attempt to 'bind' to LDAP specifying a username and password, and it will match the password for you. Or not.
In JNDI, 'bind' corresponds to LdapContext.reconnect().

Related

How to Split a String into Several Portions

I am working on an android app that summarizes text messages that are sent to clients from Financial services provider, a text message is sent as a notification each time a user makes a transaction.
Here is a sample message
[-ZAAD SHILLING-] Ref:1141125019 SLSH4,000 sent to AXMED XASAN
WARSAME(634458520) at 12/05/19 22:33:03, Your Balance is
SLSH44,222.62.
So I want to extract several portions of this message like
Ref:1141125019
Amount Sent: SLSH4,000
Recipient Name: AXMED XASAN WARSAME
Recipient Phone: 634458520
Date: 12/05/19
Time: 22:33:03
Balance: SLSH44,222.62
I have already got the text messages to appear in a listview, I now want to customize it, I don't want the whole message to appear, I just want the portion I mentioned above to appear.
Here is a Sample Code
if (Data.contains("Ref:")){
String[] Tx = Data.split("Ref:");
String TxID = Tx[1];
}
This problem would probably be best solved using regular expressions (regex)
Regular expressions allow you to match a string based on a pattern, and extract information from the string.
public static void main(String[] args) {
String data = "( [-ZAAD SHILLING-] Ref:1141125019 SLSH4,000 sent to AXMED XASAN WARSAME(634458520) at 12/05/19 22:33:03, Your Balance is SLSH44,222.62. )";
String headerReg = "\\[-([a-zA-Z\\s]+?)-]";
String refReg = "Ref:([0-9]+)";
String amountReg = "([,.\\w]+)";
String nameReg = "([\\w\\s]+?)";
String accountReg = "\\([0-9]+\\)";
String dateReg = "([0-9]{2}/[0-9]{2}/[0-9]{2})";
String timeReg = "([0-9]{2}:[0-9]{2}:[0-9]{2})";
String balanceReg = "([,.\\w]+?)";
String finalReg = "\\( " + headerReg + " " + refReg + " " + amountReg + " sent to " + nameReg + accountReg + " at " + dateReg + " " + timeReg + ", Your Balance is " + balanceReg + ". \\)";
Pattern pattern = Pattern.compile(finalReg);
Matcher matcher = pattern.matcher(data);
if (matcher.find()) {
MatchResult result = matcher.toMatchResult();
int groups = result.groupCount();
for (int i = 0; i < groups; i++) {
System.out.println(result.group(i + 1));
}
}
}
Using this, we can find the relevant data from your input string.
If the message syntax is always the same then you can use some tricky split strings like this:
String msg = "( [-ZAAD SHILLING-] Ref:1141125019 SLSH4,000 sent to AXMED XASAN WARSAME(634458520) at 12/05/19 22:33:03, Your Balance is SLSH44,222.62. )";
String ref = msg.split("Ref:")[1].split(" ")[0];
String amount = msg.split("Ref:")[1].split(" ")[1].split(" ")[0];
String recipient = msg.split("Ref:")[1].split("sent to ")[1].split("\\(")[0];
String phone = msg.split("Ref:")[1].split("sent to ")[1].split("\\(")[1].split("\\)")[0];
String date = msg.split("Ref:")[1].split("sent to ")[1].split("\\(")[1].split(" at ")[1].split(" ")[0];
String time = msg.split("Ref:")[1].split("sent to ")[1].split("\\(")[1].split(" at ")[1].split(" ")[1].split(",")[0];
String balance = msg.split("Your Balance is ")[1].split("\\)")[0];
System.out.println("ref: "+ref);
System.out.println("amount: "+amount);
System.out.println("recipient: "+recipient);
System.out.println("phone: "+phone);
System.out.println("date: "+date);
System.out.println("time: "+time);
System.out.println("balance: "+balance);
Result is:
ref: 1141125019
amount: SLSH4,000
recipient: AXMED XASAN WARSAME
phone: 634458520
date: 12/05/19
time: 22:33:03
balance: SLSH44,222.62.

Regex to pass Apache each line in logs file

I need to pass Apache log file through this regex but not working, return false.
private String accessLogRegex()
{
String regex1 = "^([\\d.]+)"; // Client IP
String regex2 = " (\\S+)"; // -
String regex3 = " (\\S+)"; // -
String regex4 = " \\[([\\w:/]+\\s[+\\-]\\d{4})\\]"; // Date
String regex5 = " \"(.+?)\""; // request method and url
String regex6 = " (\\d{3})"; // HTTP code
String regex7 = " (\\d+|(.+?))"; // Number of bytes
String regex8 = " \"([^\"]+|(.+?))\""; // Referer
String regex9 = " \"([^\"]+|(.+?))\""; // Agent
return regex1+regex2+regex3+regex4+regex5+regex6+regex7+regex8+regex9;
}
Pattern accessLogPattern = Pattern.compile(accessLogRegex());
Matcher entryMatcher;
String log = "64.242.88.10 | 2004-07-25.16:36:22 | "GET /twiki/bin/rdiff/Main/ConfigurationVariables HTTP/1.1" 401 1284 | Mozilla/4.6 [en] (X11; U; OpenBSD 2.8 i386; Nav)";
entryMatcher = accessLogPattern.matcher(log);
if(!entryMatcher.matches()){
System.out.println("" + index +" : couldn't be parsed");
}
I've include the sample of Apache log, it's pip ("|") separated.
Is there a reason you want to use regexes? These are quite error-prone, easy to get wrong, and can be a maintenance nightmare...
An alternative might be to use a library for this, for example this one
That said, if you do want to use a regex, yours contains a number of errors:
String regex1 = "^([\\d.]+)"; // while quite liberal, this should work
String regex2 = " (\\S+)"; // matches the first pipe
String regex3 = " (\\S+)"; // this will match the date field
String regex4 = " \\[([\\w:/]+\\s[+\\-]\\d{4})\\]"; // date has already been matched so this won't work, also this is all wrong
String regex5 = " \"(.+?)\""; // you're not matching the pipe character before the URL; also, why the ?
String regex6 = " (\\d{3})"; // HTTP code
String regex7 = " (\\d+|(.+?))"; // Why are you also matching any other characters than just digits?
String regex8 = " \"([^\"]+|(.+?))\""; // Your sample log line doesn't contain a referer
String regex9 = " \"([^\"]+|(.+?))\""; // Agent is not enclosed in quotes
One possible regex solution for the example log line you have given is this:
String regex1 = "^([\\d.]+)"; // digits and dots: the IP
String regex2 = " \\|"; // why match any character if you *know* there is a pipe?
String regex3 = " ((?:\\d+[-:.])+\\d+)"; // match the date; don't capture the inner group as we are only interested in the full date
String regex4 = " \\|"; // pipe
String regex5 = " \"(.+)\""; // request method and url
String regex6 = " (\\d{3})"; // HTTP code
String regex7 = " (\\d+)"; // Number of bytes
String regex8 = " \\|"; // pipe again
String regex9 = " (.+)"; // The rest of the line is the user agent
Of course this may need some further tweaking if other log lines don't follow the exact same format.

Extracting Capture Group from Non-Capture Group in Java

I have a string, let's call it output, that's equals the following:
ltm data-group internal str_testclass {
records {
baz {
data "value 1"
}
foobar {
data "value 2"
}
topaz {}
}
type string
}
And I'm trying to extract the substring between the quotes for a given "record" name. So given foobar I want to extract value 2. The substring I want to extract will always come in the form I have prescribed above, after the "record" name, a whitespace, an open bracket, a new line, whitespace, the string data, and then the substring I want to capture is between the quotes from there. The one exception is when there is no value, which will always happen like I have prescribed above with topaz, in which case after the "record" name there will just be an open and closed bracket and I'd just like to get an empty string for this. How could I write a line of Java to capture this? So far I have ......
String myValue = output.replaceAll("(?:foobar\\s{\n\\s*data "([^\"]*)|()})","$1 $2");
But I'm not sure where to go from here.
Let's start extracting "records" structure with following regex ltm\s+data-group\s+internal\s+str_testclass\s*\{\s*records\s*\{\s*(?<records>([^\s}]+\s*\{\s*(data\s*"[^"]*")?\s*\}\s*)*)\}\s*type\s*string\s*\}
Then from "records" group, just find for sucessive match against [^\s}]+\s*\{\s*(?:data\s*"(?<data>[^"]*)")?\s*\}\s*. The "data" group contains what's you're looking for and will be null in "topaz" case.
Java strings:
"ltm\\s+data-group\\s+internal\\s+str_testclass\\s*\\{\\s*records\\s*\\{\\s*(?<records>([^\\s}]+\\s*\\{\\s*(data\\s*\"[^\"]*\")?\\s*\\}\\s*)*)\\}\\s*type\\s*string\\s*\\}"
"[^\\s}]+\\s*\\{\\s*(?:data\\s*\"(?<data>[^\"]*)\")?\\s*\\}\\s*"
Demo:
String input =
"ltm data-group internal str_testclass {\n" +
" records {\n" +
" baz {\n" +
" data \"value 1\"\n" +
" }\n" +
" foobar {\n" +
" data \"value 2\"\n" +
" }\n" +
" topaz {}\n" +
" empty { data \"\"}\n" +
" }\n" +
" type string\n" +
"}";
Pattern language = Pattern.compile("ltm\\s+data-group\\s+internal\\s+str_testclass\\s*\\{\\s*records\\s*\\{\\s*(?<records>([^\\s}]+\\s*\\{\\s*(data\\s*\"[^\"]*\")?\\s*\\}\\s*)*)\\}\\s*type\\s*string\\s*\\}");
Pattern record = Pattern.compile("(?<name>[^\\s}]+)\\s*\\{\\s*(?:data\\s*\"(?<data>[^\"]*)\")?\\s*\\}\\s*");
Matcher lgMatcher = language.matcher(input);
if (lgMatcher.matches()) {
String records = lgMatcher.group();
Matcher rdMatcher = record.matcher(records);
while (rdMatcher.find()) {
System.out.printf("%s:%s%n", rdMatcher.group("name"), rdMatcher.group("data"));
}
} else {
System.err.println("Language not recognized");
}
Output:
baz:value 1
foobar:value 2
topaz:null
empty:
Alernatives: As your parsing a custom language, you can give a try to write an ANTLR grammar or create Groovy DSL.
Your regex shouldn't even compile, because you are not escaping the " inside your regex String, so it is ending your String at the first " inside your regex.
Instead, try this regex:
String regex = key + "\\s\\{\\s*\\n\\s*data\\s*\"([^\"]*)\"";
You can check out how it works here on regex101.
Try something like this getRecord() method where key is the record 'name' you're searching for, e.g. foobar, and the input is the string you want to search through.
public static void main(String[] args) {
String input = "ltm data-group internal str_testclass { \n" +
" records { \n" +
" baz { \n" +
" data \"value 1\" \n" +
" } \n" +
" foobar { \n" +
" data \"value 2\" \n" +
" }\n" +
" topaz {}\n" +
" } \n" +
" type string \n" +
"}";
String bazValue = getRecord("baz", input);
String foobarValue = getRecord("foobar", input);
String topazValue = getRecord("topaz", input);
System.out.println("Record data value for 'baz' is '" + bazValue + "'");
System.out.println("Record data value for 'foobar' is '" + foobarValue + "'");
System.out.println("Record data value for 'topaz' is '" + topazValue + "'");
}
private static String getRecord(String key, String input) {
String regex = key + "\\s\\{\\s*\\n\\s*data\\s*\"([^\"]*)\"";
final Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
//if we find a record with data return it
return matcher.group(1);
} else {
//else see if the key exists with empty {}
final Pattern keyPattern = Pattern.compile(key);
Matcher keyMatcher = keyPattern.matcher(input);
if (keyMatcher.find()) {
//return empty string if key exists with empty {}
return "";
} else {
//else handle error, throw exception, etc.
System.err.println("Record not found for key: " + key);
throw new RuntimeException("Record not found for key: " + key);
}
}
}
Output:
Record data value for 'baz' is 'value 1'
Record data value for 'foobar' is 'value 2'
Record data value for 'topaz' is ''
You could try
(?:foobar\s{\s*data "(.*)")
I think the replaceAll() isn't necessary here. Would something like this work:
String var1 = "foobar";
String regex = '(?:' + var1 + '\s{\n\s*data "([^"]*)")';
You can then use this as your regex to pass into your pattern and matcher to find the substring.
You can simple transform this into a function so that you can pass variables into it for your search string:
public static void SearchString(String str)
{
String regex = '(?:' + str + '\s{\n\s*data "([^"]*)")';
}

Extract text from string and write to another string

I have string like this: "Welcome Vitalii Mckay "
I need to cut from this string my name and surname, it should left in new string: "Mckay, Vitalii".
But it should be good not just for my name, it should works for other names with different length, for example:
"Welcome John Smith " -> "Smith, John"
or
"Welcome Andrea J. " -> "J., Andrea".
String name = "Welcome Vitalii Mckay";
String[] parts = name.split("\\ ");
name = parts[2] + ", " + parts[1];
Based on #Vishal's answer and OP's comment on #Max's answer, I believe this will work:
String name = " Welcome Vitalii Mckay "; // with spaces in the beginning and in the end
String[] parts = name.trim().split(" "); // you don't really need the \\
name = parts[2] + ", " + parts[1];
Just make sure you trim your String input.
Could you just use a delimiter?
i.e. use a delimiter to separate the three strings, and only print out the two needed values (Surname [2]/Firstname [1])
String s = "Welcome Vitalii Mckay";
String[] split = s.split("\\s+");
System.out.println(split[2] + ", " + split[1]);
// "Welcome"
// followed by the not of space one or more times
// then a space
// followed by anything one or more times
Pattern pattern = Pattern.compile("Welcome ([^ ]+) (.+)");
Matcher matcher = pattern.matcher("Welcome Vitalii Mckay");
if (!matcher.matches()) throw new Exception();
String firstName = matcher.group(1); // groups are captured between ()
String lastName = matcher.group(2); // groups are captured between ()

Java string parsing with different regex to split

str="Tick for symbol .ISEQ-IDX descriptor id 1 timestamp_sec 20130628030105 timestamp_usec 384000;EXCH_TIME 1372388465384;SENDING_TIME 0;PRICE 3957.890000;MIC XDUBIND;"
I dont have any control on changing the format of how this string is created.
I tried this but I cant really get the values of first keys "Tick for symbol","timestamp_sec" etc.
Not only in this specific string but I was curious about how to parse a string with multiple regex splits. Any help will be appreciated.
String[] s = line.split(";");
Map<String, String> m = new HashMap<String, String>();
for (int i = 0; i < s.length; i++)
{
String[] split = s[i].split("\\s+");
for (String string2 : split)
{
//Adding key value pair. to a map for further usage.
m.put(split[0], split[1]);
}
}
Edit
Desired output into a map:
(Tick for Symbol, .ISEQ-IDX)
(descriptor id, 1)
(timestamp_sec,20130628030105)
(timestamp_usec,384000)
(EXCH_TIME,1372388465384)
(SENDING_TIME,0)
(PRICE, 3957.890000)
(MIC, XDUBIND)
How about the following? You specify a list of key-value pattern pairs. Keys are specified directly as strings, values as regexes. Then you go thru this list and search the text for the key followed by the value pattern, if you find it you extract the value.
I assume the keys can be in any order, not all have to be present, there might be more than one space separating them. If you know the order of the keys, you can always start find on the place where the previous find ended. If you know all keys are obligatory, you can throw an exception if you do not find what you look for.
static String test="Tick for symbol .ISEQ-IDX descriptor id 1 timestamp_sec 20130628030105 timestamp_usec 384000;EXCH_TIME 1372388465384;SENDING_TIME 0;PRICE 3957.890000;MIC XDUBIND;";
static List<String> patterns = Arrays.asList(
"Tick for symbol", "\\S+",
"descriptor id", "\\d+",
"timestamp_sec", "\\d+",
"timestamp_usec", "\\d+",
"EXCH_TIME", "\\d+",
"SENDING_TIME","\\d+",
"PRICE", "\\d+.\\d",
"MIC", "\\S+"
);
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
for (int i = 0; i<patterns.size();i+=2) {
String key = patterns.get(i);
String val = patterns.get(i+1);
String pattern = "\\Q" +key + "\\E\\s+(" + val + ")";
Matcher m = Pattern.compile(pattern).matcher(test);
if (m.find()) {
map.put(key, m.group(1));
}
}
System.out.println(map);
}
I don't think a regex will help you here, whoever designed that output String clearly didn't have splitting in mind.
I suggest simply parsing through the String with a loop and doing the whole thing manually. Alternatively you can just look through the String for substrings (suck as "Tick for symbol"), then take whatever word comes after (until the next space), since the second parameter always seems to be one words.
Using the Pattern class from java.util.regex package, described step by step in this java Regex tutorial:
private static final Pattern splitPattern = Pattern.compile("^Tick for symbol (.*) descriptor id (\\d+) timestamp_sec (\\d+) timestamp_usec (\\d+);EXCH_TIME (\\d+);SENDING_TIME ?(\\d+);PRICE (.*);MIC (\\w+);$");
private static String printExtracted(final String str) {
final Matcher m = splitPattern.matcher(str);
if (m.matches()) {
final String tickForSymbol = m.group(1);
final long descriptorId = Long.parseLong(m.group(2), 10);
final long timestampSec = Long.parseLong(m.group(3), 10);
final long timestampUsec = Long.parseLong(m.group(4), 10);
final long exchTime = Long.parseLong(m.group(5), 10);
final long sendingTime = Long.parseLong(m.group(6), 10);
final double price = Double.parseDouble(m.group(7));
final String mic = m.group(8);
return "(Tick for Symbol, " + tickForSymbol + ")\n" +
"(descriptor id, " + descriptorId + ")\n" +
"(timestamp_sec, " + timestampSec + ")\n" +
"(timestamp_usec, " + timestampUsec + ")\n" +
"(EXCH_TIME, " + exchTime + ")\n" +
"(SENDING_TIME, " + sendingTime +")\n" +
"(PRICE, " + price + ")\n" +
"(MIC, " + mic + ")";
} else {
throw new IllegalArgumentException("Argument " + str + " doesn't match pattern.");
}
}
Edit: Using group instead of replaceAll as it makes more sense and and is also faster.

Categories

Resources