I have a string, 12999986, 31999999, 39949283, 99002999 in which I am trying to replace all of the patterns 99 with the pattern 00. However, the pattern cannot be part of a substring of another similar string, say 999 or 9999. In this example, the output would be 12999986, 31999999, 30049283, 00002999 (39949283 to 30049283, 99002999 to 00002999). I've created this method, but it doesn't really work for larger strings (doesn't find all patterns, inserts strings in random places):
public static String replaceAllExact(String data, String searchString, String replacement) {
List<Integer> locations = new ArrayList<>(); //start (exclusive)
char[] dataChars = data.toCharArray();
char[] searchStringChars = searchString.toCharArray();
char[] replacementChars = replacement.toCharArray();
int i = 0;
int k = 0;
int startIndex = 0;
int searchStringCharsLength = searchStringChars.length - 1;
for(char c : dataChars) {
if(c != searchStringChars[i] && i == 0) { //not the start of a pattern; continue
k++;
continue;
}else if(c == searchStringChars[i] && i == 0) { //might be the pattern we're looking for
startIndex = k;
i++;
}else if((c == searchStringChars[i] && i > searchStringCharsLength) || ((c != searchStringChars[i] && i < searchStringCharsLength) && i != 0)) { //pattern was too long or too short to be the pattern we're looking for
i = 0;
}else if(c == searchStringChars[i] && i < searchStringCharsLength) { //could be the pattern... keep going
i++;
}else if(c != searchStringChars[i] && i != 0 && i == searchStringCharsLength) { //this is the pattern we're looking for
locations.add(startIndex);
i = 0;
}
k++;
}
int offset = 0;
StringBuilder builder = new StringBuilder(data);
for(int l : locations) {
l += offset;
builder.delete(l, l + searchString.length());
builder.insert(l, replacementChars);
offset = (builder.length() - data.length());
}
return builder.toString();
}
How can I accomplish this? Regex solutions would be welcome, if they are possible.
Clarification
A similar string is a string in which a normal replace will replace some of the characters. For example, using the standard library replace(CharSequence target, CharSequence replacement), the string 31999999 would be considered similar because replace(99, 00) can replace some characters.
The string 39349283 is not a similar string because replace(99, 00) cannot replace any characters. The string 39949283 is similar because replace(99, 00) can replace some characters.
If I understand you correctly you want to replace 99 with something else, but only if there is no 9 before or after it.
In that case you can use look-around mechanisms and ensure that
there is no 9 before, via (?<!9)
there is no 9 after, via (?!9)
So you could use str = str.replaceAll("(?<!9)99(?!9)", "00").
Related
Trying to write a code that makes a string become altcase (ie. "hello" becomes "HeLlO". I borrowed code from another question on this forum that asked for something similar (Java Case Switcher) However, the code only switched the casing of a letter instead of having a capital letter (first), then lowercase letter, etc. pattern.
What I have so far:
public String altCase(String text)
{
String str = "";
for (int i = 0; i <= text.length(); i++)
{
char cA = text.charAt(i);
if (text.charAt(0).isUppercase)
{
str += Character.toLowerCase(cA);
}
if (text.charAt(0).isLowercase)
{
str += Character.toUpperCase;
}
if(i != 0 && Character.isUpperCase(cA))
{
if (text.charAt(i)-1.isUpperCase || text.charAt(i)+1.isUpperCase)
{
str += Character.toLowerCase(cA);
}
else
{
str += cA;
}
}
if(i != 0 && Character.isLowerCase(cA))
{
if (text.charAt(i)-1.isLowerCase || text.charAt(i)+1.isLowerCase)
{
str += Character.toUpperCase(cA);
}
else
{
str += cA;
}
}
}
return str;
}
I'm still relatively new to coding in general so please excuse my inefficiencies, as well as any headaches I might induce from the lack of experience in my coding. I cannot tell where I am going wrong except maybe when I typed "text.charAt(i)-1.isLowerCase" as the statement seems a bit illogical, but I am lost in terms of trying to come up with something else that would accomplish the same thing. Or is my error completely elsewhere? Thanks for any help in advance.
The modulus operator could take you a long way here...
StringBuilder rslt = new StringBuilder();
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
switch (i % 2) {
case 0:
rslt.append(Character.toUpperCase(c));
break;
case 1:
rslt.append(Character.toLowerCase(c));
break;
}
}
return rslt.toString();
If I truly understand what you want to get is that:
Get a string, change it in a format of AbCdEfG.... and so on.
There is more simple solution.
Get a string and with for loop, for every character, change character size depending on position in string, for i%2 == 0 upper case, and i%2 == 1 lower case.
public String altCase(String text)
{
String str = "";
for (int i = 0; i < text.length(); i++)
{
char cA = text.charAt(i);
if (i%2 == 0)
{
str += Character.toUpperCase(cA);
}
else
{
str += Character.toLowerCase(cA);
}
}
return str;
}
I would start with a StringBuilder (a mutable character sequence) of text.toLowerCase(); then set the characters at even indices to their capital equivalents (and your method doesn't appear to depend on instance state, so it might be static). Something like,
public static String altCase(String text) {
StringBuilder sb = new StringBuilder(text.toLowerCase());
for (int i = 0; i < text.length(); i += 2) {
sb.setCharAt(i, Character.toUpperCase(sb.charAt(i)));
}
return sb.toString();
}
IntStream.range(0, s.length()).mapToObj(i -> i % 2 == 0 ?
Character.toUpperCase(s.charAt(i)) :
Character.toLowerCase(s.charAt(i)))
.map(String::valueOf)
.collect(Collectors.joining());
I am trying to find out that if my string contains all the letters from a to z & A to Z. I tried below: but it will return true if it has aA. I am looking for all the 52 letters i.e. if string have all 52 letters then only it will return true else false by using Pattern and matcher.
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
s=s.replaceAll("\\s+", "");
System.out.println(s);
// String input = "[a-zA-Z]+";
String input = "\\w+";
System.out.println(input);
Pattern pr = Pattern.compile(input);
Matcher m =pr.matcher(s);
if(m.matches()){
System.out.println("pangram");
} else {
System.out.println("non-pangram");
}
We can solve this by other ways, but I am trying to solve it by only using Pattern and matcher.
If you want to see if all 52 upper- and lower-case letters are present in a given input string, you can't use a regular expression. It simply cannot do something like that.
If the list of characters that must be present is dynamic, you can use this method:
private static boolean containsAllOf(String input, String alphabet) {
boolean[] found = new boolean[alphabet.length()];
int foundCount = 0;
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
int idx = alphabet.indexOf(ch);
if (idx >= 0 && ! found[idx]) {
found[idx] = true;
if (++foundCount == found.length)
return true;
}
}
return false;
}
E.g. use it like this:
containsAllOf("abc", "abcdef") // returns false
containsAllOf("dfu hadkf kojuhoeuaf", "abcdef") // returns false
containsAllOf("bad fed", "abcdef") // returns false
containsAllOf("bad fec", "abcdef") // returns true
Performance can be improved if you specifically want to check the entire 52 upper- and lower-case letters of the English alphabet.
private static boolean containsAllOfAlphabet(String input) {
boolean[] found = new boolean[52];
int foundCount = 0;
for (int i = 0; i < input.length(); i++) {
char ch = input.charAt(i);
int idx = (ch >= 'a' && ch <= 'z' ? ch - 'a' :
ch >= 'A' && ch <= 'Z' ? ch - 'A' + 26 : -1);
if (idx >= 0 && ! found[idx]) {
found[idx] = true;
if (++foundCount == found.length)
return true;
}
}
return false;
}
UPDATE If you want to use a pattern matcher, here is one way.
Start by sorting all the characters of the input string, then use a pattern matcher to eliminate all non-letters and duplicate letters. If the length of the result is 52, then all letters are present.
Of course, a pangram normally don't consider uppercase and lowercase letters to be different, so calling toLowercase() and checking for length 26 may be more correct:
String input = "Pack my box with five dozen liquor jugs.";
char[] buf = input.toLowerCase().toCharArray();
Arrays.sort(buf);
boolean pangram = (new String(buf).replaceAll("[^a-zA-Z]|([a-zA-Z])\\1+", "$1").length() == 26);
System.out.println(pangram ? "pangram" : "non-pangram");
I have used set and putting the every character(ASC) in it, as Set only contains the unique values so I am checking size == 26 for all characters. use if(put>=97 && put<=122 ) before adding.
Scanner sc = new Scanner(System.in);
String s= sc.nextLine();
Set<Integer> h = new HashSet<Integer>();
for (int i = 0; i < s.length(); i++) {
int put = (int)s.charAt(i);
if(put>=97 && put<=122 ) {
h.add(put);
}
if(put>=65 && put<=90 ) {
h.add(put);
}
}
if(h.size()==52)
System.out.println("all 52");
else
System.out.println("missing");
I wrote the following code but similar characters are always in the same case. What's wrong in this code and How can this problem be solved??
private void genBTActionPerformed(java.awt.event.ActionEvent evt) {
String str = new String(strTF.getText());
int n = str.length();
char ch;
int i;
for(i = 0; i < n; i++) {
if(i % 2 == 0) {
ch = Character.toLowerCase(str.charAt(i));
str = str.replace(str.charAt(i), ch);
} else {
ch = Character.toUpperCase(str.charAt(i));
str = str.replace(str.charAt(i), ch);
}
}
jumTF.setText(str);
}
Unlike what its name says, .replace() replaces characters/CharSequences in the whole input. The difference with .replaceAll() is that it takes literals as arguments and not regexes/regex replacements strings (and that it has an overload taking two chars as arguments). That is the second worst misnamed method of the String class after matches().
Moreover you create a new String on each character you replace, so you have n+1 strings for a n character long string. Do it like this instead:
final char[] chars = str.toCharArray();
final int len = chars.length;
char c;
for (int i = 0; i < len; i++) {
c = chars[i];
chars[i] = i % 2 == 0
? Character.toLowerCase(c)
: Character.toUpperCase(c);
}
jumTF.setText(new String(chars));
In your program you were using replace() which replaces characters/CharSequences in the whole input what you need to do is
Put the string into an array.
Iterate over said array.
convert that array back into string
private void genBTActionPerformed(java.awt.event.ActionEvent evt) {
String str = new String(strTF.getText());
char [] chr= str.toCharArray();
int n = chr.length;
char ch;
int i;
for(i = 0; i < n; i++) {
if(i % 2 == 0) {
ch = Character.toLowerCase(chr[i]);
chr[i]=ch;
} else {
ch = Character.toUpperCase(chr[i]);
chr[i]=ch;
}
}
jumTF.setText(new String(chr)); }
hope this will help you :)
Since String are immutable in java , you can use StringBuilder or StringBuffer to solve this problem
StringBuilder str=new StringBuilder(inputString);
You can use your own logic just with slight change instead of using
str = str.replace(str.charAt(i), ch);//since it replaces in whole string
Use
str.setCharAt(i,ch);
So your final Program looks like this :
for(i = 0; i < n; i++) {
if(i % 2 == 0) {
ch = Character.toLowerCase(str.charAt(i));
str.setCharAt(i,ch);
} else {
ch = Character.toUpperCase(str.charAt(i));
str.setCharAt(i,ch);
}
}
Suppose InputString is : stackoverflow
then output is : sTaCkOvErFlOw
I'm reading text where I want to find the end of the first sentence, at this point the first index of either '.', '?', or '!' in a string. So here's my Java code:
int next = -1;
int nextQ = text.indexOf("? ");
int nextE = text.indexOf("! ");
int nextDot = text.indexOf(". ");
if (nextDot > 0) {
next = nextDot;
if (nextQ > 0){
if (nextQ < next) {next = nextQ;}
if (nextE > 0) {
if (nextE < next) {next = nextE;}
}
} else if (nextE > 0){
if (nextE < next) {next = nextE;}
}
} else if (nextQ > 0){
next = nextQ;
if (nextE > 0 && nextE < next){next = nextE;}
} else if (nextE > 0) { next = nextE;}
I believe the code works but that's a total of 10 if statements, which doesn't look too neat. I might want to add more sentence delimiters there but I don't think this approach is very flexible. Is there any better way of doing the same? Any shorter way of achieving the same result? ...or should I try some other programming language for this sort of problems? Which one?
I'd suggesting using a regular expression to search for any of those delimiters at once.
String text = <TEXT>;
int next;
Pattern p = Pattern.compile("\\? |! |\\. ");
Matcher m = p.matcher(text);
if (m.find()) {
int next = m.start();
} else next = -1;
You can change the regex to adjust exactly what is matched. For example, I'd suggest that instead of requiring exactly a space after the delimiter, you instead require any whitespace character, so that a line break or tab will also work. This would be as follows: "\\?\\s|!\\s|\\.\\s". You would be able to add extra delimiters in a similar manner, and with a little extra work be able to detect which delimiter was triggered.
The documentation for Java regular expressions in the Pattern class is here and a useful tutorial here.
Use methods to keep DRY:
int firstDelimiterIndex(String s) {
return minIndex(s.indexOf(". "), minIndex(s.indexOf("? "), s.indexOf("! ")));
}
int minIndex(int a, int b) {
if (a == -1) return b;
if (b == -1) return a;
return Math.min(a, b);
}
Or choose a faster algorithm:
for (int i = 0; i < s.length; i++) {
switch (s.charAt(i)) {
case '.':
case '?':
case '!':
if (i + 1 < s.length() && s.charAt(i + 1) == ' ')
return i;
}
}
Use Math.min and a small modification.
First, turn -1 into large positive integers:
int largeMinusOne(int a)
{
return a==-1 ? 9999999 : a;
}
int nextQ = largeMinusOne(text.indexOf("? "));
int nextE = largeMinusOne(...);
int nextDot = largeMinuseOne(...);
And now:
int next = Math.min(Math.min(nextQ, nextE), nextDot);
You may like to just filter out values, which are not ok ( == -1) (Java 8):
int nextQ = text.indexOf("? ");
int nextE = text.indexOf("! ");
int nextDot = text.indexOf(". ");
OptionalInt res = IntStream.of(nextQ, nextE, nextDot).filter(i -> i != -1).min();
if (res.isPresent())
// ok, using res.get()
else
// none of these substrings found
It's more a joke, than a real answer, in real life gandaliter's answer should be used.
I would suggest just looping through the string character by character and stopping when you encounter any of those characters. What you're doing now is many times less efficient.
I have a string line like the following :
A:B:C:D:E:F:G:H:I:J:K:L:M
It means delimiter ( : ) count is 12 . This line is valid.
Now suppose you have a following line :
A:B:C:D:E:F:G:H:::::
This line is also valid because it contains 12 delimiter . where 8 values are present and 4 values are blank.
Now the following line should be invalid :
A:B:C:D:E:F: -- Invalid - because it contains only 6 values but expected are 12.
how to do this .. ? I tried the following code , but not getting the desired output :
String strLine = "A:B:C:D:E:F:G:H:::::" ;
int delimiterCount = 12 ;
String[] ValuesArray = strLine.split(":");
if(ValuesArray.length != delimiterCounter){
System.out.println(Invalid);
}else {
System.out.println("ValidLine");
}
I am getting the output as Invalid where as it sould be Valid.
Use following method to count occurance of particular String
public static int countOccurance(String inputString, String key) {
int index = 0;
int fromIndex = 0;
int result = 0;
if (inputString == null || key == null) {
return 0;
}
while ((index = inputString.indexOf(key, fromIndex)) != -1) {
result++;
fromIndex = index + key.length();
}
return result;
}
If you want to use split, and it's not a bad approach really (although it might be for this particular situation), you need to pass -1 as the second argument to split otherwise it removes empty strings.
See http://ideone.com/gaUw5.
It is good to know this about split. Some languages require the -1 and some do not.
The code
class Main {
public static void main(String[] args) {
String line = "A:B:C:D:E:F:G:H:::::" ;
int delimiterCount = 12 ;
String[] values = line.split(":", -1);
if (values.length != delimiterCount + 1) {
System.out.println("Invalid Line");
} else {
System.out.println("Valid Line");
}
}
}
It should be
String strLine = "A:B:C:D:E:F:G:H: : : : : " ;
int delimiterCount = 12 ;
String[] ValuesArray = strLine.split(":");
if((ValuesArray.length - 1) != delimiterCounter){
System.out.println(Invalid);
}else {
System.out.println("ValidLine");
}
as array will have values not delimeter
No reason to use regex here. If the only criteria for checking the validity of an input is 12 delimeters :, just count them.
String strLine = "A:B:C:D:E:F:G:H:::::";
int EXPECTED_DELIMETERS = 12;
int delimiterCount = 0;
for (int idx = 0; idx < strLine.length(); idx++) {
if (strLine.charAt(idx) == ':') {
delimiterCount++;
}
}
if (EXPECTED_DELIMETERS == delimiterCount) {
System.out.println("ValidLine");
} else {
System.out.println("Invalid");
}
Concise Java 8 solution:
private static boolean isValid(String content, char delimiter, int count) {
return count == content.chars().filter(c -> c == delimiter).count();
}