Check that string contains a character from array - java

I would like to check that string that is a filename contains a illegal argument from the ILLEGAL_CHARACTERS. Simply I could use for loop, but I want to do this by Streams.
My code:
package shared;
import java.util.Arrays;
public class Validator {
private static final Character[] ILLEGAL_CHARACTERS =
{'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'};
public static boolean fileNameIsValid(String fileName) {
return Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(fileName::contains);
}
}
Problem is in contains method cuz It needs a CharSequence instead of char. Is there any way to do this by stream without changing Character[] type to String[]?

Streams might not the best fit here. Also, now your solution has quadratic complexity (N*M, where N is the file name length, and M is the size of your illegal character array), which is not very performant. As proposed in the comments, you could use a regular expression:
private static final Pattern ILLEGAL_CHARACTERS_REGEX =
Pattern.compile("[/\n\r\t\0\f`?*\\\\<>|\":]");
public static boolean fileNameIsValidRegex(String fileName) {
return !ILLEGAL_CHARACTERS_REGEX.matcher(fileName).find();
}
Or, if your illegal character set is limited to ASCII, you could play around with a bitset to squeeze some performance:
private static final BitSet ILLEGAL_CHARACTERS = new BitSet();
static {
for (char c : new char[]{
'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'}) {
ILLEGAL_CHARACTERS.set(c);
}
}
public static boolean fileNameIsValid(String fileName) {
return fileName.chars().noneMatch(ILLEGAL_CHARACTERS::get);
}

You can try to use indexOf:
return Arrays.stream(ILLEGAL_CHARACTERS)
.map(fileName::indexOf)
.anyMatch(i -> i >= 0);

First, I would recommend that you use a Set instead of an array, because you don't have any need for indexing your stuff, then Stream over the characters from the given string, and check if there is any match with your set.
Get the chars from the chars() method on a string, this will give you a array of integeres, which you then can cast to an char "array"
Here's all you need:
private static final Set<Character> ILLEGAL_CHARACTERS = Set.of(
'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':');
public static boolean fileNameIsValid(String fileName) {
return fileName.chars()
.mapToObj(c -> (char) c)
.noneMatch(ILLEGAL_CHARACTERS::contains);
}

If contains method needs a CharSequence instead of char, then you can give it to it:
Arrays.stream(ILLEGAL_CHARACTERS)
.map(String::valueOf)
.anyMatch(fileName::contains);
But under the hood in the String class, this method uses indexOf(String str) method:
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
So, to avoid redundant type conversion, you can use another indexOf(int ch) method:
Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(ch -> fileName.indexOf(ch) > -1);
See also: How to “subtract” 2 given strings In Java?

Related

StringUtils Overload chop method

I want to overload the chop method of StringUtils to remove the last character if it is a backslash(\).
Is it possible to overload the function or I need to use an if condition?
Why not this instead?
StringUtils.removeEnd(s,"\\")
yes, use an if statement. You can't override a static method and it would be too much anyway to create it's own class just for that.
I have an alternative that I personally like:
public static String chopIf(Predicate<String> p, String s) {
if (p.test(s)) {
return s.substring(0, s.length()-1); //or StringUtils.chop(s)
}
return s;
}
public static void main(String[] args) {
String test = "qwert\\";
System.out.println(chopIf(s -> s.endsWith("\\"), test));
}
Something like that. Then you can use it for any character. Tweak it according to need.

How can I pass two types of unlimited variables [duplicate]

Is there any way in Java to create a method, which is expecting two different varargs?
I know, with the same object kind it isn't possible because the compiler doesn't know where to start or to end. But why it also isn't possible with two different Object types?
For example:
public void doSomething(String... s, int... i){
//...
//...
}
Is there any way to create a method like this?
Thank you!
Only one vararg, sorry. But using asList() makes it almost as convenient:
public void myMethod(List<Integer> args1, List<Integer> args2) {
...
}
-----------
import static java.util.Arrays.asList;
myMethod(asList(1,2,3), asList(4,5,6));
In Java, only one varargs argument is allowed and it must be the last parameter of the signature.
But all it does it convert it to an array anyway, so you should just make your two parameters explicit arrays:
public void doSomething(String[] s, int[] i){
A possible API design in which the calling code looks like
doSomething("a", "b").with(1,2);
through "fluent" API
public Intermediary doSomething(String... strings)
{
return new Intermediary(strings);
}
class Intermediary
{
...
public void with(int... ints)
{
reallyDoSomething(strings, ints);
}
}
void reallyDoSomething(String[] strings, int[] ints)
{
...
}
The danger is if the programmer forgot to call with(...)
doSomething("a", "b"); // nothing is done
Maybe this is a little better
with("a", "b").and(1, 2).doSomething();
Only one vararg is allowed. This is because multiple vararg arguments are ambiguous. For example, what if you passed in two varargs of the same class?
public void doSomething(String...args1, String...args2);
Where does args1 end and args2 begin? Or how about something more confusing here.
class SuperClass{}
class ChildClass extends SuperClass{}
public void doSomething(SuperClass...args1, ChildClass...args2);
ChildClass extends SuperClass, and so is can legally exist in args1, or args2. This confusion is why only one varargs is allowed.
varargs must also appear at the end of a method declaration.
Just declare the specific type instead as 2 arrays.
Although this kind of thing is occasionally useful, usually if you find that you are hitting a restriction in Java you could probably redesign something and come out much better. Here are some possible other ways to look at it...
If the two lists are related at all you probably want to create a wrapper class for the two different lists and pass in the wrapper. Wrappers around collections are almost always a good idea--they give you a place to add code that relates to the collection.
If this is a way to initialize data, parse it from a string. For instance, "abc, 123:def, 456:jhi,789" is almost embarassingly easy to split up with 2 split statements and a loop (2-3 lines of code). You can even make a little custom parser class that parses a string like that into a structure you feed into your method.
Hmm--honestly asside from initializing data I don't even know why you'd want to do this anyway, any other case and I expect you'd be passing in 2 collections and wouldn't be interested in varags at all.
You can do something like this, then you can cast and add additional logic inside that method.
public void doSomething(Object... stringOrIntValues) {
...
...
}
And use this method like so:
doSomething(stringValue1, stringValue2, intValue1, intValue2,
intValue3);
This is an old thread, but I thought this would be helpful regardless.
The solution I found isn't very neat but it works. I created a separate class to handle the heavy lifting. It only has the two variables I needed and their getters. The constructor handles the set methods on its own.
I needed to pass direction objects and a respective Data object. This also solves the possible problem of uneven data pairs, but that is probably only for my usage needs.
public class DataDirectionPair{
Data dat;
Directions dir;
public DataDirectionPair(Data dat, Directions dir) {
super();
this.dat = dat;
this.dir = dir;
}
/**
* #return the node
*/
public Node getNode() {
return node;
}
/**
* #return the direction
*/
public Directions getDir() {
return dir;
}
}
I would then just pass this class as the vararg for the method
public void method(DataDirectionPair... ndPair){
for(DataDirectionPair temp : ndPair){
this.node = temp.getNode();
this.direction = temp.getDir();
//or use it however you want
}
}
It is not possible because the Java Language Specification says so (see 8.4.1. Formal Parameters):
The last formal parameter of a method or constructor is special: it
may be a variable arity parameter, indicated by an ellipsis
following the type.
Note that the ellipsis (...) is a token unto itself (§3.11). It is possible to put whitespace between it and the type, but this is
discouraged as a matter of style.
If the last formal parameter is a variable arity parameter, the method
is a variable arity method. Otherwise, it is a fixed arity method.
As to why only one and only the last parameter, that would be a guess, but probably because allowing that could lead to undecidable or ambiguous problems (eg consider what happens with method(String... strings, Object... objects)), and only allowing non-intersecting types would lead to complications (eg considering refactorings where previously non-intersecting types suddenly are), lack of clarity when it does or does not work, and complexity for the compiler to decide when it is applicable or not.
I just read another question about this "pattern", but it is already removed, so I would like to propose a different approach to this problem, as I didn't see here this solution.
Instead to force the developer to wrapping the inputs parameter on List or Array, it will be useful to use a "curry" approach, or better the builder pattern.
Consider the following code:
/**
* Just a trivial implementation
*/
public class JavaWithCurry {
private List<Integer> numbers = new ArrayList<Integer>();
private List<String> strings = new ArrayList<String>();
public JavaWithCurry doSomething(int n) {
numbers.add(n);
return this;
}
public JavaWithCurry doSomething(String s) {
strings.add(s);
return this;
}
public void result() {
int sum = -1;
for (int n : numbers) {
sum += n;
}
StringBuilder out = new StringBuilder();
for (String s : strings) {
out.append(s).append(" ");
}
System.out.println(out.toString() + sum);
}
public static void main(String[] args) {
JavaWithCurry jwc = new JavaWithCurry();
jwc.doSomething(1)
.doSomething(2)
.doSomething(3)
.doSomething(4)
.doSomething(5)
.doSomething("a")
.doSomething("b")
.doSomething("c")
.result();
}
}
As you can see you in this way, you could add new elements of which type you need when you need.
All the implementation is wrapped.
If you are not going to be passing a large number of Strings most of the time for the first argument you could provide a bunch of overloads that take different numbers of Strings and wrap them in an array before calling a method that takes the array as the first argument.
public void doSomething(int... i){
doSomething(new String[0], i);
}
public void doSomething(String s, int... i){
doSomething(new String[]{ s }, i);
}
public void doSomething(String s1, String s2, int... i){
doSomething(new String[]{ s1, s2 }, i);
}
public void doSomething(String s1, String s2, String s3, int... i){
doSomething(new String[]{ s1, s2, s3 }, i);
}
public void doSomething(String[] s, int... i) {
// ...
// ...
}
follwing on Lemuel Adane (cant comment on the post, due to lack of rep :))
if you use
public void f(Object... args){}
then you may loop using How to determine an object's class (in Java)?
like for instance
{
int i = 0;
while(i< args.length && args[i] instanceof String){
System.out.println((String) args[i]);
i++ ;
}
int sum = 0;
while(i< args.length){
sum += (int) args[i];
i++ ;
}
System.out.println(sum);
}
or anything you intend to do.
You can convert your varargs to arrays
public void doSomething(String[] s, int[] i) {
...
}
then with some helper methods to convert your varargs to array like this:
public static int[] intsAsArray(int... ints) {
return ints;
}
public static <T> T[] asArray(T... ts) {
return ts;
}
Then you can use those helper methods to convert your vararged parameters.
doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));

Detecting type of operator stored as string in java [duplicate]

This question already has answers here:
Is it possible to pass arithmetic operators to a method in java?
(9 answers)
Closed 6 years ago.
In a Java program, I have these strings:
a= 8,7,"+"
b=1,5,"*"
Each line is a separate process. I want in each line, that two number calculated with that operator. But I don't want to use any type of condition system for detecting which operator is in each line.
In fact, my main problem is detecting the type of the operator without conditions. I don't want to use the Javascript engine. I want to know is there any efficient and standard way.
Another solution from J. Selva's response:
Improvements
single class
static block
better abstraction
import java.util.HashMap;
import java.util.Map;
/**
* Created by SEA-HAWK on 23/8/15.
*/
public abstract class Expr {
public static Map<String,Object> op;
static{
op=new HashMap<>();
op.put("+", new Expr() {
#Override
public int evaluate(int a, int b) {
return a + b;
}
});
op.put("-", new Expr() {
#Override
public int evaluate(int a, int b) {
return a - b;
}
});
op.put("*", new Expr() {
#Override
public int evaluate(int a, int b) {
return a * b;
}
});
op.put("/", new Expr() {
#Override
public int evaluate(int a, int b) {
return a / b; // decimal point loss
}
});
}
abstract public int evaluate(int a, int b);
public static int exprEval(String expr){
String a[]=expr.split(",");
a[2]=a[2].replaceAll("\"","");
return ((Expr)op.get(a[2])).evaluate(Integer.parseInt(a[0]),Integer.parseInt(a[1]));
}
}
Main function:
public static void main(String[] args) {
String x="20,10,\"*\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"+\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"-\"";
System.out.println(x+"="+Expr.exprEval(x));
x="20,10,\"/\"";
System.out.println(x+"="+Expr.exprEval(x));
}
Output:
20,10,"*"=200
20,10,"+"=30
20,10,"-"=10
20,10,"/"=2
Note: change datatype for float/decimal value computation.
First Split the string and store the operator in the Character variable. You can use split() to split a String and assign it to a String array. Access operator using the array index and assign it to a Character variable.
Now You can use Map<Character,Object> where you can store character and object to calculate in single structure and access later with character only without any if-else or switch.
Map<Character,Object> map = new HashMap<>();
map.put('+', plusObject);
map.put('-', minusObject);
map.put('*', multiplyObject);
map.put('/', divideObject);
To get the object type of operator, you can use map.get(character) it will return the object according to the character and null otherwise.
Update: Create four classes and a object for each class namely plusObject, minusObject, multiplyObject,divideObject. These are the objects that you add to HashMap initially. Have a evaluate() function in each class. Now with the returned object, call the evaluate() method which will make call to respective class. You need not check the Object type using any conditional statements.
You can convert the postfix expression into infix mathematical expression and execute it using expression evaluator in Java or javascript(not preferred). As you recommend java, following link will help you:
evaluating-a-math-expression-given-in-string-form
java-parse-a-mathematical-expression-given-as-a-string-and-return-a-number
Answer from above two links:
You can pass it to a BeanShell bsh.Interpreter, something like this:
Interpreter interpreter = new Interpreter();
interpreter.eval("result = 5+4*(7-15)");
System.out.println(interpreter.get("result"));
Let us know if your issue gets resolved.

Method with two indeterminate arguments?

I understand now how to create limitless arguments as per Java method with unlimited arguments
But I was wondering what is the syntax to extend this to two arguments, akin to printf?
I want to create unlimited String, int pairs.
The goal would be to display String1 : Int1, String2: Int2 and so on. I'm just not sure what the syntax would be, let alone if it's possible.
It's not directly possible but here are some approaches:
If the strings will be unique, you can pass the data as a Map:
public void method(Map<String,Integer> pairs) {
...
}
You can use two separate arrays:
public void method(String[] strings, int[] ints) {
if (strings.length != ints.length) throw new IllegalArgumentException();
...
}
Call as:
method(new String[] { "a", "b", "c" }, new int[] { 1, 2, 3 });
Use Object for everything and sort it out later. This suffers from ugly internals and a lack of compile-time type checking but it has the shortest calling syntax:
public void method(Object... args) {
if (args.length % 2 != 0) throw new IllegalArgumentException();
for (int i = 0; i < args.length; i += 2) {
String s = (String)args[i + 0];
int i = (Integer)args[i + 1];
...
}
}
Use a builder-style object:
public Pairs method() {
return new Pairs();
}
// make the names here meaningful for what your method actually does
public static class Pairs {
private static class Pair {
String s;
int i;
}
private final List<Pair> pairs = new ArrayList<>();
private Pairs() {}
public Pairs add(String s, int i) {
Pair p = new Pair();
p.s = s;
p.i = i;
pairs.add(p);
return this;
}
public void run() {
for (Pair p : pairs) {
... do method's work here ...
}
}
}
Depending on what you want to achieve this might be over-complicating it, but it gives a quite pleasant and fully type-checked syntax for the caller:
method()
.add("a", 1)
.add("b", 2)
.add("c", 3)
.run();
Well, firstly, you can't do this:
public void foo(String... strings, int... ints) {
Since you'll get an error that the varargs parameter strings needs to be the last one.
So you'll likely want to make a small wrapper class, say StringWithInt and then do like so:
public void foo(StringWithInt... values) {
I hope this helps!
Make the argument one Object argument, which has its own problems...
public void foo(Object... things)
But probably the best idea is to use a generic list for each argument type :
public void foo(List<String> strings, List<Integer> integers) {}
If the method specifically requires matchigng pairs a Map<String, Integer> could also be used.
(no you can't to original question)
hmmm why don't you just mapping instead?
Something like this
public void foo(Map<String,Integer> map){
}
Or maybe instead of String and int, just use objects?
public void foo(Object... args){
}

compareTo() method is not overriding default method when using Comparable interface

I am trying to overwrite the default compareTo() method in java by writing my own and using implements comparable, however it seems that java is still using the default method.
I am trying to sort an array of Strings by length that I get from a .dat file, however it keeps sorting it by alphabetic order instead. I would appreciate it if someone could tell me what I am doing wrong as I cannot figure out why this does not work.
Thanks
import static java.lang.System.*;
import java.util.Arrays;
public class Word implements Comparable
{
private String word;
private String[] array;
public Word()
{
word = "";
}
public Word(String s)
{
word = s;
}
public void setWord(String s)
{
word = s;
}
public int compareTo(String rhs)
{
String temp = (String)rhs;
if(word.length() > temp.length())
return 1;
else if(word.length() < temp.length())
return -1;
return 0;
}
public void setSize(int size)
{
array = new String[size];
}
public void add(int spot, String other)
{
array[spot] = other;
}
public String[] sortByLength()
{
Arrays.sort(array);
return array;
}
public String toString()
{
return Arrays.toString(array);
}
}
Here is the class that contains the main method
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.Arrays;
import static java.lang.System.*;
public class Lab18d
{
public static void main( String args[] ) throws IOException
{
Scanner file = new Scanner(new File("lab18d.dat"));
int size = file.nextInt();
file.nextLine();
Word test = new Word();
test.setSize(size);
String word = "";
for(int i = 0; i < size; i++)
{
word = file.next();
test.setWord(word);
test.add(i, word);
}
test.sortByLength();
System.out.println(test);
}
}
Do yourself a favour: every time you override a method, add the #Override annotation to it. This will give you a compile error if you make a mistake in overriding the method, which is what is happening here. You are implementing it wrong, as Comparable (the "raw" form of Comparable<T> does not declare a method compareTo(String), it declares a method compareTo(Object).
To get it to compile as is, you would need to accept an Object instead of a String or implement Comparable<String> instead of Comparable.
But that would really be incorrect in most cases, because such a comparison is not symmetric: you can compare a Word to a String but not a String to a word.
Most likely you want to implement Comparable<Word> instead of Comparable and accept a Word to compareTo().
#Override
public int compareTo(Word other)
{
String temp = other.word;
//...
}
Note though that Comparable is only a really good fit when a type is intrinsically ordered (what the docs call a "natural order") like dates or numbers. Since you are not actually comparing the two words alphabetically (which would be the closest to a String's natural order) this is a better candidate for using an external comparator.
//since Word.word is a private member, this either needs to be nested inside of Word
//or Word.word would need to be given an accessor method
public static class LengthComparator implements Comparator<Word> {
#Override
public int compare(Word word1, Word word2) {
return Integer.valueOf(word1.word.length()).compareTo(word2.word.length());
}
}
Comparable is typed, but you're using the raw type. Try this:
public class Word implements Comparable<Word> { // Note: typing of Comparable
...
public int compareTo(Word rhs) { // Note: parameter is typed
String temp = rhs.word;
return word.length() - temp.length(); // Note: Simplification of code
}
}
Check the signature of compareTo method here
It should be int compareTo(Object o)
and you are giving public int compareTo(String rhs)
You can also add #Override annotation to your method. It will let you know if you are not following proper signature.
The short version: You need to use the Arrays.sort method taking a Comparator instead.
The long version: The line
Arrays.sort(array);
in the sortByLength method keeps calling the compareTo methods on the objects it's sorting - and those objects are strings! Instead, you need the line
Arrays.sort(array, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
if (s1.length() > s2.length())
return 1;
if (s1.length() < s2.length())
return -1;
return 0;
}
});
or you can create a separate class implementing Comparator<String> and use an instance of that as the second argument to Arrays.sort.

Categories