I am doing below steps.
match sms with regex
if contains specified keyword then get values from sms body like amount,description (reason of transaction), Account number(if ATM withdraw),transaction type(debit/credit)
this regex not matching all kind of bank/transaction sms thus it is not efficient , is there any other way to identify bank message.
example sms :
1) Dear Customer, your Account Number XXXXXX6377 has been credited by Rs 215.000 being DBT/DBTL funds transfer on 19/05/2015 - CENTRAL BANK OF INDIA
2)A/c NN5715 debited for Rs 2000; ATM WDL. A/c Bal(sub to chq realisatn) Rs13286.23 on 24APR 21:19hr. Call 1800226999 to block your card if not used by you.
3) Dear Customer, Your Ac XXXXXXXX5666 is credited with INR8,922.00 on 16 Feb. Info. INF*000080483346*SALARY. Your Net Available Bal is INR 8,922.00.
private static ArrayList<SmsDto> parsevalues(ArrayList<SmsDto> body_val) {
ArrayList<SmsDto> resSms = new ArrayList<>();
for (int i = 0; i < body_val.size(); i++) {
SmsDto smsDto = body_val.get(i);
Pattern regEx
= Pattern.compile("(?:inr|rs)+[\\s]*[0-9+[\\,]*+[0-9]*]+[\\.]*[0-9]+");
// Find instance of pattern matches
Matcher m = regEx.matcher(smsDto.getBody());
if (m.find()) {
try {
Log.e("amount_value= ", "" + m.group(0));
String amount = (m.group(0).replaceAll("inr", ""));
amount = amount.replaceAll("rs", "");
amount = amount.replaceAll("inr", "");
amount = amount.replaceAll(" ", "");
amount = amount.replaceAll(",", "");
smsDto.setAmount(Double.valueOf(amount));
if (smsDto.getBody().contains("debited") ||
smsDto.getBody().contains("purchasing") || smsDto.getBody().contains("purchase") || smsDto.getBody().contains("dr")) {
smsDto.setTransactionType("0");
} else if (smsDto.getBody().contains("credited") || smsDto.getBody().contains("cr")) {
smsDto.setTransactionType("1");
}
smsDto.setParsed("1");
Log.e("matchedValue= ", "" + amount);
if (!Character.isDigit(smsDto.getSenderid().charAt(0)))
resSms.add(smsDto);
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.e("No_matchedValue ", "No_matchedValue ");
}
}
return resSms;
}
For finding out amount from bank transaction message.
(?i)(?:(?:RS|INR|MRP)\.?\s?)(\d+(:?\,\d+)?(\,\d+)?(\.\d{1,2})?)
For finding out merchant name from bank transaction message.
(?i)(?:\sat\s|in\*)([A-Za-z0-9]*\s?-?\s?[A-Za-z0-9]*\s?-?\.?)
For finding out card name(debit/credit card) from bank transaction message.
(?i)(?:\smade on|ur|made a\s|in\*)([A-Za-z]*\s?-?\s[A-Za-z]*\s?-?\s[A-Za-z]*\s?-?)
In python following Regex can be helpful.
For finding amount in bank messages
[rR][sS]\.?\s[,\d]+\.?\d{0,2}|[iI][nN][rR]\.?\s*[,\d]+\.?\d{0,2}
For finding A/C no
[0-9]*[Xx\*]*[0-9]*[Xx\*]+[0-9]{3,}
The following two regular expressions helped in finding amount from most of the bank transactions(HDFC, ICICI, ING, KOTAK, SBI, CANARA, PNB):
[Ii][Nn][Rr](\\s*.\\s*\\d*)
[rR][sS](\\s*.\\s*\\d*)
Please comment if you have figured out much better expressions than the above.
Please Check in this link:-https://github.com/vikashstm/transactionsmsfilter
Here maximum , banking filter added.
It has also get through message:-
Deducted Amount,
balance message identified and get available message
Account Number
Transaction Mode
Reference Number/transaction Information etc...
To detect any transactional message in android :
"(?=.*[Aa]ccount.*|.*[Aa]/[Cc].*|.*[Aa][Cc][Cc][Tt].*|.*[Cc][Aa][Rr][Dd].*)(?=.*[Cc]redit.*|.*[Dd]ebit.*)(?=.*[Ii][Nn][Rr].*|.*[Rr][Ss].*)"
tested on several bank messages
Please check https://github.com/minimal-scouser/trny
Usage:
import { getTransactionInfo } from "trny";
const message = "Your a/c XX0413 is debited on 15/12/2020 by INR 3,211.00 towards purchase. Avl Bal: INR 5,603.54.";
const info = getTransactionInfo(message);
/*
info = {
account: {
type: "account",
no: "0413"
},
balance: "5603.54",
money: "3211.00",
typeOfTransaction: "debited"
}
*/
It also has methods like
getAccount
getMoneySpent
getBalance
This needs more testing but see if this solves your problem.
Related
I am trying to extract values from a given text.
Here is the text:
String 1: $.675.00 was spent on your CAPITAL ONE CREDIT Card ending 2123 on 2015-05-04:15:28:08 at Best Buy
String 2: $ 1,310.00 was spent on your Credit Card 5178XXXXXXXX6040 on MAY-04-15 at Amazon Stores.
I want to extract the following from string:
Amount after $
Credit Card text
Credit card number (in this case - 2123 or 5178XXXXXXXX6040)
at which place (in this case Best Buy or Amazon Stores).
To start I was trying extract all the numbers from the string: I tried the following:
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(string1);
Log.e("Value","from String"+m.group(0));
I am always getting the following error:
05-05 10:09:35.532: E/AndroidRuntime(13618): java.lang.IllegalStateException: No successful match so far
05-05 10:09:35.532: E/AndroidRuntime(13618): at java.util.regex.Matcher.ensureMatch(Matcher.java:471)
05-05 10:09:35.532: E/AndroidRuntime(13618): at java.util.regex.Matcher.group(Matcher.java:578)
Why isn't it matching even though the text has numbers?
Thanks!
As #justhecuke told there is no strict format for your string values to split using Patterns so I did using String functions, give a try
String crType1 = "CREDIT Card ending ";//mind the space at end
String crType2 = "Credit Card ";//mind the space at end
String rate, cardNo, at;
if (string1.contains(crType1)) {
rate = getStringValue(string1, "$", " ");
cardNo = getStringValue(string1, crType1, " ");
at = getAddress(string1);
} else {
rate = getStringValue(string1, "$", " ");
cardNo = getStringValue(string1, crType2, " ");
at = getAddress(string1);
}
System.out.println(String.format("Rate : %s Card No : %s Address : %s", rate, cardNo, at));
Methods
public static String getAddress(String string) {
return string.substring(string.lastIndexOf("at") + 2, string.length()).trim();
}
public static String getStringValue(String string, String startString, String endString) {
int startAt = string.indexOf(startString) + startString.length();
int endAt = string.indexOf(endString, startAt);
return string.substring(startAt, endAt).trim();
}
By the time you call m.group(0) you haven't actually told it to try to match stuff yet. This is why it gives you an IllegalStateException.
Try:
while(m.find()) {
Log.e("Value",String.format("From String: '%s'", m.group()));
}
i am about to create a validation for phone number format..The format is 10 digit including the plus sign eg:+0133999504. Even though I have declare the pattern which is I try to disallow the "-" symbol or any other characters, but the validation is not working. Any other Idea or solution?
1st I declared the string regex:
String PhoneNo;
String PhoneNo_PATTERN ="[\\+]\\d{3}\\d{7}";
2nd I make a if..else statement:
{
Pattern pattern = Pattern.compile(PhoneNo_PATTERN);
Matcher matcher = pattern.matcher(PhoneNo);
if (!matcher.matches())
{
inputemergencyContactNo.setError("Please enter Emergency Contact No");
}
else{
Toast.makeText(RiderProfile.this, "Please filled in All field", Toast.LENGTH_SHORT).show();
}
Why not remove all non-digits and then count the digits left and put the plus back in later? This allows users the freedom to fill out their phone number anyway they want...
String PhoneNo = "+123-456 7890";
String Regex = "[^\\d]";
String PhoneDigits = PhoneNo.replaceAll(Regex, "");
if (PhoneDigits.length()!=10)
{
// error message
}
else
{
PhoneNo = "+";
PhoneNo = PhoneNo.concat(PhoneDigits); // adding the plus sign
// validation successful
}
If your app is intended for international use replace
if (!PhoneDigits.length()!=10)
with
if(PhoneDigits.length() < 6 || PhoneDigits.length() > 13)
as Fatti Khan suggested.
To apply this in the code you posted at Android EditText Validation and Regex first include this method in your public class or the class containing onClick():
public boolean validateNumber(String S) {
String Regex = "[^\\d]";
String PhoneDigits = S.replaceAll(Regex, "");
return (PhoneDigits.length()!=10);
}
And include this method in the CreateNewRider class:
protected String tidyNumber(String S) {
String Regex = "[^\\d]";
String PhoneDigits = S.replaceAll(Regex, "");
String Plus = "+";
return Plus.concat(PhoneDigits);
}
This is where the validation happens...
#Override
public void onClick(View view) {
Boolean b = false;
if(inputfullname.getText().toString().equals("")) b = true;
else if(... // do this for all fields
else if(inputmobileNo.getText().toString().equals("")) b=true;
else if(inputemergencyContactNo.getText().toString().equals("")) b=true;
else {
if(validateNumber( inputmobileNo.getText().toString() )
Toast.makeText(RiderProfile.this, "Invalid mobile number", Toast.LENGTH_SHORT).show();
else if(validateNumber( inputemergencyContactNo.getText().toString() )
Toast.makeText(RiderProfile.this, "Invalid emergency contact number", Toast.LENGTH_SHORT).show();
else {
// Validation succesful
new CreateNewRider().execute();
}
}
if(b) Toast.makeText(RiderProfile.this, "Please filled in All field", Toast.LENGTH_SHORT).show();
}
And then use tidyNumber() in the CreateNewRider class:
protected String doInBackground(String... args) {
String fullname= inputfullname.getText().toString();
String IC= inputIC.getText().toString();
String mobileNo= tidyNumber( inputmobileNo.getText().toString() );
String emergencyContactName= inputemergencyContactName.getText().toString() );
String emergencyContactNo= tidyNumber( inputemergencyContactNo.getText().toString() );
...
Given the rules you specified:
upto length 13 and including character + infront.
(and also incorporating the min length of 10 in your code)
You're going to want a regex that looks like this:
^\+[0-9]{10,13}$
With the min and max lengths encoded in the regex, you can drop those conditions from your if() block.
Off topic: I'd suggest that a range of 10 - 13 is too limiting for an international phone number field; you're almost certain to find valid numbers that are both longer and shorter than this. I'd suggest a range of 8 - 20 to be safe.
[EDIT] OP states the above regex doesn't work due to the escape sequence. Not sure why, but an alternative would be:
^[+][0-9]{10,13}$
[EDIT 2] OP now adds that the + sign should be optional. In this case, the regex needs a question mark after the +, so the example above would now look like this:
^[+]?[0-9]{10,13}$
For Valid Mobile You need to consider 7 digit to 13 digit because some country have 7 digit mobile number . Also we can not check like mobile number must starts with 9 or 8 or anything..
For mobile number I used this this Function
private boolean isValidMobile(String phone2)
{
boolean check;
if(phone2.length() < 6 || phone2.length() > 13)
{
check = false;
txtPhone.setError("Not Valid Number");
}
else
{
check = true;
}
return check;
}
^[\\+]\\d{3}\\d{7}$
Use anchors to limit the match.
^ => start of match
$=> end of match
To validate India's mobile number.
Your edit text input
edt_mobile.text.toString().trim()
Number validation method
fun isValidMobile(phone: String): Boolean {
return phone.matches(Constants.REGEX_MOBILE.toRegex()) && phone.trim().length == 10
}
Regression expression
const val REGEX_MOBILE = "^[6-9]{1}[0-9]{9}\$"
I am allowing the user to choose a phone number from their address book. I need the number to always be in the international format, however sometimes people store a local number without the country code in their contacts (ex. 555-555-5555 instead of +1-555-555-5555).
Is there an easy way to find out what country code the local number implies so I can add it manually?
This is what you need
https://code.google.com/p/libphonenumber/
String numberString = "044 668 18 00"
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
PhoneNumber numberProto = phoneUtil.parse(numberString, "BH"); // Where BH is the user's iso country code
String finalNumber = phoneUtil.format(numberProto, PhoneNumberFormat.E164);
} catch (NumberParseException e) {
System.err.println("NumberParseException was thrown: " + e.toString());
}
I have a string like this : +33123456789 (french phone number). I want to extract the country code (+33) without knowing the country. For example, it should work if i have another phone from another country. I use the google library https://code.google.com/p/libphonenumber/.
If I know the country, it is cool I can find the country code :
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
int countryCode = phoneUtil.getCountryCodeForRegion(locale.getCountry());
but I don't find a way to parse a string without to know the country.
Okay, so I've joined the google group of libphonenumber ( https://groups.google.com/forum/?hl=en&fromgroups#!forum/libphonenumber-discuss ) and I've asked a question.
I don't need to set the country in parameter if my phone number begins with "+". Here is an example :
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
try {
// phone must begin with '+'
PhoneNumber numberProto = phoneUtil.parse(phone, "");
int countryCode = numberProto.getCountryCode();
} catch (NumberParseException e) {
System.err.println("NumberParseException was thrown: " + e.toString());
}
I have got kept a handy helper method to take care of this based on one answer posted above:
Imports:
import com.google.i18n.phonenumbers.NumberParseException
import com.google.i18n.phonenumbers.PhoneNumberUtil
Function:
fun parseCountryCode( phoneNumberStr: String?): String {
val phoneUtil = PhoneNumberUtil.getInstance()
return try {
// phone must begin with '+'
val numberProto = phoneUtil.parse(phoneNumberStr, "")
numberProto.countryCode.toString()
} catch (e: NumberParseException) {
""
}
}
In here you can save the phone number as international formatted phone number
internationalFormatPhoneNumber = phoneUtil.format(givenPhoneNumber, PhoneNumberFormat.INTERNATIONAL);
it return the phone number as
International format +94 71 560 4888
so now I have get country code as this
String countryCode = internationalFormatPhoneNumber.substring(0,internationalFormatPhoneNumber.indexOf('')).replace('+', ' ').trim();
Hope this will help you
Here is a solution to get the country based on an international phone number without using the Google library.
Let me explain first why it is so difficult to figure out the country. The country code of few countries is 1 digit, 2, 3 or 4 digits. That would be simple enough. But the country code 1 is not just used for US, but also for Canada and some smaller places:
1339 USA
1340 Virgin Islands (Caribbean Islands)
1341 USA
1342 not used
1343 Canada
Digits 2..4 decide, if it is US or Canada or ... There is no easy way to figure out the country, like the first xxx are Canada, the rest US.
For my code, I defined a class which holds information for ever digit:
public class DigitInfo {
public char Digit;
public Country? Country;
public DigitInfo?[]? Digits;
}
A first array holds the DigitInfos for the first digit in the number. The second digit is used as an index into DigitInfo.Digits. One travels down that Digits chain, until Digits is empty. If Country is defined (i.e. not null) that value gets returned, otherwise any Country defined earlier gets returned:
country code 1: byPhone[1].Country is US
country code 1236: byPhone[1].Digits[2].Digits[3].Digits[6].Country is Canada
country code 1235: byPhone[1].Digits[2].Digits[3].Digits[5].Country is null. Since
byPhone[1].Country is US, also 1235 is US, because no other
country was found in the later digits
Here is the method which returns the country based on the phone number:
/// <summary>
/// Returns the Country based on an international dialing code.
/// </summary>
public static Country? GetCountry(ReadOnlySpan<char> phoneNumber) {
if (phoneNumber.Length==0) return null;
var isFirstDigit = true;
DigitInfo? digitInfo = null;
Country? country = null;
foreach (var digitChar in phoneNumber) {
var digitIndex = digitChar - '0';
if (isFirstDigit) {
isFirstDigit = false;
digitInfo = ByPhone[digitIndex];
} else {
if (digitInfo!.Digits is null) return country;
digitInfo = digitInfo.Digits[digitIndex];
}
if (digitInfo is null) return country;
country = digitInfo.Country??country;
}
return country;
}
The rest of the code (digitInfos for every country of the world, test code, ...) is too big to be posted here, but it can be found on Github:
https://github.com/PeterHuberSg/WpfWindowsLib/blob/master/WpfWindowsHelperLib/CountryCode.cs
The code is part of a WPF TextBox and the library contains also other controls for email addresses, etc. A more detailed description is on CodeProject: International Phone Number Validation Explained in Detail
Change 23.1.23: I moved CountryCode.cs to WpfWindowsHelperLib, which doesn't have any WPF dependencies, despite it's name.
Use a try catch block like below:
try {
const phoneNumber = this.phoneUtil.parseAndKeepRawInput(value, this.countryCode);
}catch(e){}
If the string containing the phone number will always start this way (+33 or another country code) you should use regex to parse and get the country code and then use the library to get the country associated to the number.
Here's a an answer how to find country calling code without using third-party libraries (as real developer does):
Get list of all available country codes, Wikipedia can help here:
https://en.wikipedia.org/wiki/List_of_country_calling_codes
Parse data in a tree structure where each digit is a branch.
Traverse your tree digit by digit until you are at the last branch - that's your country code.
If we have a phone number like 358541321 without a country code, sometimes when phone rings it says (+56 - 358541321) or +56358541321.
How to detect whether the ringed number is first number?
The number is not saved in phone memory in order to phone lookup.
https://developer.android.com/reference/android/telephony/PhoneNumberUtils.html
provides a neat solution:
import android.telephony.PhoneNumberUtils;
...
String one = "+51 - 3245678";
String two = "+513245678";
boolean isSame = PhoneNumberUtils.compare(one, two);
The usual solution to this problem is just to compare the last X (e.g. 7 or 8, depending on your country) digits of the number. In rare cases, this can lead to false positives, but usually it's a good approximation and it avoids the problem of different or missing country or area codes.
Java regular expression and String function replaceAll can do this easily.
this way,
String one = "+51 - 3245678";
String two = "+513245678";
one = one.replaceAll("[^0-9]","");
two = two.replaceAll("[^0-9]","");
Toast.makeText(this, one+" -- "+two, Toast.LENGTH_LONG).show();
if(one.equalsIgnoreCase(two))
{
Toast.makeText(this, "Both Are Equal", Toast.LENGTH_LONG).show();
}
else
{
Toast.makeText(this, "Different", Toast.LENGTH_LONG).show();
}