How to check if an integer matches given expression of "5+4n"? - java

What can be an efficient way to determine if a given integer matches the result of an expression 5+4n. Say, I have a number 54 and I want to check if expression given above can result in this number. One way I can think of is to evaluate 5+4n up to 54 and check if the result matches the number of interest. But it will be an inefficient way to go when I'll have to check big numbers.

If we are assuming that x will always be greater than or equal to 0, x=5+4n can be rewritten as x=1+4(n+1).
This means that when x is divided by 4, there will be a remainder of 1. So you can simply do the below:
private boolean doesMatch(x number) {
return x%4==1;
}

if you want to evaluate the expression A+Bn, with A and B configurable, you should extract A and B first:
Pattern p = Pattern.compile("(\\-?\\d+)\\s*\\+([\\-\\+]?\\d+)\\s*n");
Matcher m = p.matcher(expression);
if (m.matches()) {
int A = Integer.valueOf(m.group(1));
int B = Integer.valueOf(m.group(2));
// Evaluate expression
...
}
and then simply check if x is a solution:
// Evaluate expression
if ((x-A) % B == 0) {
// Number is a solution
} else {
// Number is not a solution for the expression
}

Related

Regex contain only numbers and does not contain only 0

I would like to implement a regular expression that return true if:
The string contain only number
The string does not contain only 0 ( like 0000)
For example:
1230456 => true
888822200000 => true
00000000 => false
fff => false
I started to implement this
private static final String ARTICLE_VALID_FORMAT = "\\d";
private static final Pattern ARTICLE_VALID_FORMAT_PATTERN = Pattern.compile(ARTICLE_VALID_FORMAT);
private boolean isArticleHasValidFormat(String article) {
return StringUtils.isNotBlank(article) && ARTICLE_VALID_FORMAT_PATTERN.matcher(article).matches();
}
Now, it returns true if the article has only number. but i would like to test also if it is not all 0.
How to do that?
Thanks
You can use:
private static final String ARTICLE_VALID_FORMAT = "[0-9]*?[1-9][0-9]*";
which means:
Match zero or more digits; the ? means to match as few as possible before moving onto the next part
then one digit that's not a zero
then zero or more digits
Or, as Joachim Sauer suggested in comments:
private static final String ARTICLE_VALID_FORMAT = "0*[1-9][0-9]*";
which means:
Match zero or more zeros
then one digit that's not a zero
then zero or more digits
If you wanted to do it without regex, you could use (among many other ways):
string.chars().allMatch(c -> c >= '0' && c <= '9')
&& string.chars().anyMatch(c -> c != '0')
The regex pattern \d*[1-9]\d* as given by #AndyTurner is a good way to do this. Another approach would be to try to parse the string input to a long, and then check that it is greater than zero:
private boolean isArticleHasValidFormat(String article) {
try {
if (Long.parseLong(article) > 0) return true;
}
catch (NumberFormatException e) {
}
return false;
}
This solution assumes that you are only concerned with finding positive numbers. If not, and you want to cater to negatives, then check num != 0 instead.
Try this condition.
(Integer.pasrseInt("0" + article.replaceAll("^[0-9]", "0")) != 0) ? true : false
the ["0" +] is to avoid NumberFormatException for empty string
You don't need to make a Pattern object. Just call matches function from the String class
article.matches("\\d*[1-9]\\d*");
It's the same regex as Andy Turner suggested.

Java Regex to Match a Number Within a Range

I'm trying to craft a Java regular expression to identify if a number (which I don't know until execution time) is within a range (and that range I also don't know until execution time).
Specifically, I'm trying to use Cisco's PRIME compliance module to validate my switch has no inactive VLANs (for this question, a VLAN is just a number), but PRIME uses Java regular expression syntax.
I know that the specific switch command I'm evaluating uses a syntax like:
switchport trunk allowed vlan 1,20,37,45,90-101,300-502,904-2044
How, then, can I tell if VLAN "x" is in any of those ranges?
If x = 20, it should match.
If x = 90, it should match.
If x = 900, it should fail.
If x = 1043, it should match.
Any ideas?
Edit: Unfortunately, the RegEx listed here is for ranges that are known; the examples are all hard-coded ranges. I need something that takes an unknown x, y, and z, where all x, y, and z might possibly be 1, 2, 3, or 4 digits, and matches if z is between x and y when written as "x-y".
Is there a way to take the string "x-y", parse it into \1 and \2 that are understood to be numbers, and match if (z >= \1 && z <= \2)?
I've tried looking at things like lookahead and lookbehind and crazy/obscure Java-compatible regex structures, but my head quickly got spun into the 4th dimension.
I don't think this should be done with a regular expression. Personally I'd use a regex to check if it's the right format, i.e. check if the string matches "VLAN ([0-9]+(-[0-9]+)?)(,([0-9]+(-[0-9]+)?))*", then split the latter part on the commas and use integer parsing from there, depending on if there is a '-' in there or not you can check the ranges.
For instance like this: https://jsfiddle.net/gcb9pm7f/15/
function testRanges()
{
var str = document.getElementById("textField").value;
var test = parseInt(document.getElementById("numberField").value);
str = str.toUpperCase(); // VLAN big
var regex = /^VLAN ([0-9]+(-[0-9]+)?)(,([0-9]+(-[0-9]+)?))*$/g;
if (regex.test(str))
{
str = str.substring(5, str.length); // remove 'VLAN'
var splitArray = str.split(',');
for (var idx = 0; idx < splitArray.length; idx++)
{
var rangeStr = splitArray[idx];
if (rangeStr.includes('-'))
{
// range, check both values.
var a = parseInt(rangeStr.split('-')[0]);
var b = parseInt(rangeStr.split('-')[1]);
if (a > b)
{
if (test >= b && test <= a) return true; // range is inclusive
}
else // a <= b
{
if (test <= b && test >= a) return true; // range is inclusive
}
}
else // not a range, single value
{
if (parseInt(rangeStr) === test) return true;
}
}
}
return false; // no match or regex not matching.
}
Adjust to your programming language as needed. Should be fairly straight forward.

finding the middle index of a substring when there are duplicates in the string

I was working on a Java coding problem and encountered the following issue.
Problem:
Given a string, does "xyz" appear in the middle of the string? To define middle, we'll say that the number of chars to the left and right of the "xyz" must differ by at most one
xyzMiddle("AAxyzBB") → true
xyzMiddle("AxyzBBB") → false
My Code:
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)result=false;
if(str.length()==3 && str.equals("xyz"))result=true;
for(int j=0;j<str.length()-3;j++){
if(str.substring(j,j+3).equals("xyz")){
String rightSide=str.substring(j+3,str.length());
int rightLength=rightSide.length();
String leftSide=str.substring(0,j);
int leftLength=leftSide.length();
int diff=Math.abs(rightLength-leftLength);
if(diff>=0 && diff<=1)result=true;
else result=false;
}
}
return result;
}
Output I am getting:
Running for most of the test cases but failing for certain edge cases involving more than once occurence of "xyz" in the string
Example:
xyzMiddle("xyzxyzAxyzBxyzxyz")
My present method is taking the "xyz" starting at the index 0. I understood the problem. I want a solution where the condition is using only string manipulation functions.
NOTE: I need to solve this using string manipulations like substrings. I am not considering using list, stringbuffer/builder etc. Would appreciate answers which can build up on my code.
There is no need to loop at all, because you only want to check if xyz is in the middle.
The string is of the form
prefix + "xyz" + suffix
The content of the prefix and suffix is irrelevant; the only thing that matters is they differ in length by at most 1.
Depending on the length of the string (and assuming it is at least 3):
Prefix and suffix must have the same length if the (string's length - the length of xyz) is even. In this case:
int prefixLen = (str.length()-3)/2;
result = str.substring(prefixLen, prefixLen+3).equals("xyz");
Otherwise, prefix and suffix differ in length by 1. In this case:
int minPrefixLen = (str.length()-3)/2;
int maxPrefixLen = minPrefixLen+1;
result = str.substring(minPrefixLen, minPrefixLen+3).equals("xyz") || str.substring(maxPrefixLen, maxPrefixLen+3).equals("xyz");
In fact, you don't even need the substring here. You can do it with str.regionMatches instead, and avoid creating the substrings, e.g. for the first case:
result = str.regionMatches(prefixLen, "xyz", 0, 3);
Super easy solution:
Use Apache StringUtils to split the string.
Specifically, splitByWholeSeparatorPreserveAllTokens.
Think about the problem.
Specifically, if the token is in the middle of the string then there must be an even number of tokens returned by the split call (see step 1 above).
Zero counts as an even number here.
If the number of tokens is even, add the lengths of the first group (first half of the tokens) and compare it to the lengths of the second group.
Pay attention to details,
an empty token indicates an occurrence of the token itself.
You can count this as zero length, count as the length of the token, or count it as literally any number as long as you always count it as the same number.
if (lengthFirstHalf == lengthSecondHalf) token is in middle.
Managing your code, I left unchanged the cases str.lengt<3 and str.lengt==3.
Taking inspiration from #Andy's answer, I considered the pattern
prefix+'xyz'+suffix
and, while looking for matches I controlled also if they respect the rule IsMiddle, as you defined it. If a match that respect the rule is found, the loop breaks and return a success, else the loop continue.
public boolean xyzMiddle(String str) {
boolean result=false;
if(str.length()<3)
result=false;
else if(str.length()==3 && str.equals("xyz"))
result=true;
else{
int preLen=-1;
int sufLen=-2;
int k=0;
while(k<str.lenght){
if(str.indexOf('xyz',k)!=-1){
count++;
k=str.indexOf('xyz',k);
//check if match is in the middle
preLen=str.substring(0,k).lenght;
sufLen=str.substring(k+3,str.lenght-1).lenght;
if(preLen==sufLen || preLen==sufLen-1 || preLen==sufLen+1){
result=true;
k=str.length; //breaks the while loop
}
else
result=false;
}
else
k++;
}
}
return result;
}

java regular expression detect a double is surrounded by ceil()

I have a string like "something...ceil(0.9)...something".
I'm using Pattern p = Pattern.compile(".*ceil(.*[0-9]*\\.+[0-9]+)+.*"); to detect if the double is surrounded by ceil(). But it does not work. Any one help?
".*ceil\\(\\d+(.\\d+)?\\).*"
Matches numbers like 1, 738294, ect (no decimal point) or 2.3 4432.12634 (number dot number).
If you want to accept numers like .5, change the first + to a *.
This is a basic one to start with:
ceil\\([0-9]+\\.[0-9]*\\)
You could be more explicit around defining the number in the brackets but you do need to escape the brackets.
Try using this site for regular expression testing: http://regexpal.com/
I don't get; the Math#ceil(double) method takes a double as an argument but anyway, instead of regex, perhaps you should try simply parsing the argument passed in to the ceil method as a double; if it throws an exception, it means that it isn't a valid double:
private boolean validArgument(final String string){
final int start = string.indexOf("ceil(");
if(start < 0)
return false;
final int end = string.indexOf(')');
if(end < start || end < 0)
return false;
try{
Double.parseDouble(string.substring(start, end));
return true;
}catch(Exception ex){
return false;
}
}
And for usage, it would be like:
final boolean valid = validArgument("Math.ceil(45.97)"); which should return true.

How can I change my regex to correctly match float literals?

I am attempting to create a parser for java expressions, but for some reason I am unable to match floating point values. I am using a java.util.Matcher obtained from
Matcher token = Pattern.compile(
"(\\w[\\w\\d]*+)|" + //identifiers as group 1
"((?:(?>[1-9][0-9]*+\\.?[0-9]*+)|(?>\\.[0-9]++))(?:[Ee][+-]?[0-9]++)?)|" + //literal numbers
"([^\\w\\d\\s]*+)" //operators as group 3
).matcher();
This is intended to match an identifier, a floating point value, or an operator (I still need to refine that part of the match though will refine that part of the match later). However, I am having an issue with it in that
Below is the code that is using that expression, which is intended to take all the identifiers, numbers, and operators, register all the numbers in vars, and put all the identifiers, each number's corresponding value, and all the operators in tokens in same order as in the original string.
It does not succeed in doing so, however, because for an input string like foo 34.78e5 bar -2.7 the resulting list is '[34, A, , bar, , -, 2, B, ]' with A=-78000.0 and B=-0.7. It is supposed to return '[foo, A, bar, B]` with A=3478000 and B=-2.7. I beleive it may be just that it is failing to include both parts of the number as the match of the regex, however that may not be the case.
I have tried removing the atomic grouping and possesives from the regex, however that did not change anything.
LinkedList<String> tokens = new LinkedList<String>();
HashMap<String, Double> vars = new HashMap<String, Double>();
VariableNamer varNamer = new VariableNamer();
for(Matcher token = Pattern.compile(
"(\\w[\\w\\d]*+)|" + //variable names as group 1
"((?:(?:[1-9][0-9]*+\\.?[0-9]*+)|(?:\\.[0-9]++))(?:[Ee][+-]?[0-9]++)?)|" +
//literal numbers as group 2
"([^\\w\\d\\s]*+)" //operators as group 3
).matcher(expression); token.find();){
if(token.group(2) != null) { //if its a literal number, register it in vars and substitute a string for it
String name = varNamer.next();
if (
tokens.size()>0 &&
tokens.get(tokens.size()-1).matches("[+-]") &&
tokens.size()>1?tokens.get(tokens.size()-2).matches("[^\\w\\d\\s]"):true
)
vars.put(name, tokens.pop().equals("+")?Double.parseDouble(token.group()):-Double.parseDouble(token.group()));
else
vars.put(name, Double.parseDouble((token.group())));
tokens.addLast(name);
} else {
tokens.addLast(token.group());
}
}
and here is VariableNamer:
import java.util.Iterator;
public class VariableNamer implements Iterator<String>{
StringBuffer next = new StringBuffer("A");
#Override
public boolean hasNext() {
return true;
}
#Override
public String next() {
try{
return next.toString();
}finally{
next.setCharAt(next.length()-1, (char) (next.charAt(next.length()-1) + 1));
for(int idx = next.length()-1; next.charAt(idx) + 1 > 'Z' && idx > 0; idx--){
next.setCharAt(idx, 'A');
next.setCharAt(idx - 1, (char) (next.charAt(idx - 1) + 1));
}
if (next.charAt(0) > 'Z'){
next.setCharAt(0, 'A');
next.insert(0, 'A');
}
}
}
#Override
public void remove() {
throw new UnsupportedOperationException();
}
}
Depending on details of your expression mini-language, it is either close to the limit on what is possible using regexes ... or beyond it. And even if you do succeed in "parsing", you will be left with the problem of mapping the "group" substrings into a meaningful expression.
My advice would be to take an entirely different approach. Either find / use an existing expression library, or implement expression parsing using a parser generator like ANTLR or Javacc.

Categories