I have a few strings which are like this:
text (255)
varchar (64)
...
I want to find out the number between ( and ) and store that in a string. That is, obviously, store these lengths in strings.
I have the rest of it figured out except for the regex parsing part.
I'm having trouble figuring out the regex pattern.
How do I do this?
The sample code is going to look like this:
Matcher m = Pattern.compile("<I CANT FIGURE OUT WHAT COMES HERE>").matcher("text (255)");
Also, I'd like to know if there's a cheat sheet for regex parsing, from where one can directly pick up the regex patterns
I would use a plain string match
String s = "text (255)";
int start = s.indexOf('(')+1;
int end = s.indexOf(')', start);
if (end < 0) {
// not found
} else {
int num = Integer.parseInt(s.substring(start, end));
}
You can use regex as sometimes this makes your code simpler, but that doesn't mean you should in all cases. I suspect this is one where a simple string indexOf and substring will not only be faster, and shorter but more importantly, easier to understand.
You can use this pattern to match any text between parentheses:
\(([^)]*)\)
Or this to match just numbers (with possible whitespace padding):
\(\s*(\d+)\s*\)
Of course, to use this in a string literal, you have to escape the \ characters:
Matcher m = Pattern.compile("\\(\\s*(\\d+)\\s*\\)")...
Here is some example code:
import java.util.regex.*;
class Main
{
public static void main(String[] args)
{
String txt="varchar (64)";
String re1=".*?"; // Non-greedy match on filler
String re2="\\((\\d+)\\)"; // Round Braces 1
Pattern p = Pattern.compile(re1+re2,Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
Matcher m = p.matcher(txt);
if (m.find())
{
String rbraces1=m.group(1);
System.out.print("("+rbraces1.toString()+")"+"\n");
}
}
}
This will print out any (int) it finds in the input string, txt.
The regex is \((\d+)\) to match any numbers between ()
int index1 = string.indexOf("(")
int index2 = string.indexOf(")")
String intValue = string.substring(index1+1, index2-1);
Matcher m = Pattern.compile("\\((\\d+)\\)").matcher("text (255)");
if (m.find()) {
int len = Integer.parseInt (m.group(1));
System.out.println (len);
}
Related
I have a file name with this format yy_MM_someRandomString_originalFileName.
example:
02_01_fEa3129E_my Pic.png
I want replace the first 2 underscores with / so that the example becomes:
02/01/fEa3129E_my Pic.png
That can be done with replaceAll, but the problem is that files may contain underscores as well.
#Test
void test() {
final var input = "02_01_fEa3129E_my Pic.png";
final var formatted = replaceNMatches(input, "_", "/", 2);
assertEquals("02/01/fEa3129E_my Pic.png", formatted);
}
private String replaceNMatches(String input, String regex,
String replacement, int numberOfTimes) {
for (int i = 0; i < numberOfTimes; i++) {
input = input.replaceFirst(regex, replacement);
}
return input;
}
I solved this using a loop, but is there a pure regex way to do this?
EDIT: this way should be able to let me change a parameter and increase the amount of underscores from 2 to n.
You could use 2 capturing groups and use those in the replacement where the match of the _ will be replaced by /
^([^_]+)_([^_]+)_
Replace with:
$1/$2/
Regex demo | Java demo
For example:
String regex = "^([^_]+)_([^_]+)_";
String string = "02_01_fEa3129E_my Pic.png";
String subst = "$1/$2/";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
String result = matcher.replaceFirst(subst);
System.out.println(result);
Result
02/01/fEa3129E_my Pic.png
Your current solution has few problems:
It is inefficient - because each replaceFirst need to start from beginning of string so it needs to iterate over same starting characters many times.
It has a bug - because of point 1. while iterating from beginning instead of last modified place, we can replace value which was inserted previously.
For instance if we want to replace single character two times, each with X like abc -> XXc after code like
String input = "abc";
input = input.replaceFirst(".", "X"); // replaces a with X -> Xbc
input = input.replaceFirst(".", "X"); // replaces X with X -> Xbc
we will end up with Xbc instead of XXc because second replaceFirst will replace X with X instead of b with X.
To avoid that kind of problems you can rewrite your code to use Matcher#appendReplacement and Matcher#appendTail methods which ensures that we will iterate over input once and can replace each matched part with value we want
private static String replaceNMatches(String input, String regex,
String replacement, int numberOfTimes) {
Matcher m = Pattern.compile(regex).matcher(input);
StringBuilder sb = new StringBuilder();
int i = 0;
while(i++ < numberOfTimes && m.find() ){
m.appendReplacement(sb, replacement); // replaces currently matched part with replacement,
// and writes replaced version to StringBuilder
// along with text before the match
}
m.appendTail(sb); //lets add to builder text after last match
return sb.toString();
}
Usage example:
System.out.println(replaceNMatches("abcdefgh", "[efgh]", "X", 2)); //abcdXXgh
first;snd;3rd;4th;5th;6th;...
How can I split the above after the third occurence of the ; separator? Especially without having to value.split(";") the whole string as an array, as I won't need the values separated. Just the first part of the string up until nth occurence.
Desired output would be:
first;snd;3rd.
I just need that as a string substring, not as split separated values.
Use StringUtils.ordinalIndexOf() from Apache
Finds the n-th index within a String, handling null. This method uses String.indexOf(String).
Parameters:
str - the String to check, may be null
searchStr - the String to find, may be null
ordinal - the n-th searchStr to find
Returns:
the n-th index of the search String, -1 (INDEX_NOT_FOUND) if no match or null string input
Or this way, no libraries required:
public static int ordinalIndexOf(String str, String substr, int n) {
int pos = str.indexOf(substr);
while (--n > 0 && pos != -1)
pos = str.indexOf(substr, pos + 1);
return pos;
}
I would go with this, easy and basic:
String test = "first;snd;3rd;4th;5th;6th;";
int result = 0;
for (int i = 0; i < 3; i++) {
result = test.indexOf(";", result) +1;
}
System.out.println(test.substring(0, result-1));
Output:
first;snd;3rd
You can ofc change the 3 in the loop with the number of arguments you need
If you want to use regular expressions, it is pretty straightforward:
import re
value = "first;snd;3rd;4th;5th;6th;"
reg = r'^([\w]+;[\w]+;[\w]+)'
re.match(reg, value).group()
Outputs:
"first;snd;3rd"
More options here .
You could use a regex that uses a negated character class to match from the start of the string not a semicolon.
Then repeat a grouping structure 2 times that matches a semicolon followed by not a semicolon 1+ times.
^[^;]+(?:;[^;]+){2}
Explanation
^ Assert the start of the string
[^;]+ Negated character class to match not a semicolon 1+ times
(?: Start non capturing group
;[^;]+ Match a semicolon and 1+ times not a semi colon
){2} Close non capturing group and repeat 2 times
For example:
String regex = "^[^;]+(?:;[^;]+){2}";
String string = "first;snd;3rd;4th;5th;6th;...";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
System.out.println(matcher.group(0)); // first;snd;3rd
}
See the Java demo
If you don't want to use split, just use indexOf in a for loop to know the index of the 3rd and 4th ";" then do a substring between these index.
Also you can do a split with a regex that match the 3rd ; but it's probably not the best solution.
If you need to do this frequently it is best to compile the regex upfront in a static Pattern instance:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NthOccurance {
static Pattern pattern=Pattern.compile("^(([^;]*;){3}).*");
public static void main(String[] args) {
String in="first;snd;3rd;4th;5th;6th;";
Matcher m=pattern.matcher(in);
if (m.matches())
System.out.println(m.group(1));
}
}
Replace the '3' by the number of elements you want.
Below code find index of 3rd occurence of ';' character and make substring.
String s = "first;snd;3rd;4th;5th;6th;";
String splitted = s.substring(0, s.indexOf(";", s.indexOf(";", s.indexOf(";") + 1) + 1));
For the life of me, I can't figure out why this regular expression is not working. It should find upper case letters in the given string and give me the count. Any ideas are welcome.
Here is the unit test code:
public class RegEx {
#Test
public void testCountTheNumberOfUpperCaseCharacters() {
String testStr = "abcdefghijkTYYtyyQ";
String regEx = "^[A-Z]+$";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(testStr);
System.out.printf("Found %d, of capital letters in %s%n", matcher.groupCount(), testStr);
}
}
It doesn't work because you have 2 problems:
Regex is incorrect, it should be "[A-Z]" for ASCII letter or \p{Lu} for Unicode uppercase letters
You're not calling while (matcher.find()) before matcher.groupCount()
Correct code:
public void testCountTheNumberOfUpperCaseCharacters() {
String testStr = "abcdefghijkTYYtyyQ";
String regEx = "(\\p{Lu})";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(testStr);
while (matcher.find())
System.out.printf("Found %d, of capital letters in %s%n",
matcher.groupCount(), testStr);
}
UPDATE: Use this much simpler one-liner code to count number of Unicode upper case letters in a string:
int countuc = testStr.split("(?=\\p{Lu})").length - 1;
You didn't call matches or find on the matcher. It hasn't done any work.
getGroupCount is the wrong method to call. Your regex has no capture groups, and even if it did, it wouldn't give you the character count.
You should be using find, but with a different regex, one without anchors. I would also advise using the proper Unicode character class: "\\p{Lu}+". Use this in a while (m.find()) loop, and accumulate the total number of characters obtained from m.group(0).length() at each step.
This should do what you're after,
#Test
public void testCountTheNumberOfUpperCaseCharacters() {
String testStr = "abcdefghijkTYYtyyQ";
String regEx = "[A-Z]+";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(testStr);
int count = 0;
while (matcher.find()) {
count+=matcher.group(0).length();
}
System.out.printf("Found %d, of capital letters in %s%n", count, testStr);
}
It should find upper case letters in the given string and give me the count.
No, it shouldn't: the ^ and $ anchors prevent it from doing so, forcing to look for a non-empty string composed entirely of uppercase characters.
Moreover, you cannot expect a group count in an expression that does not define groups to be anything other than zero (no matches) or one (a single match).
If you insist on using a regex, use a simple [A-Z] expression with no anchors, and call matcher.find() in a loop. A better approach, however, would be calling Character.isUpperCase on the characters of your string, and counting the hits:
int count = 0;
for (char c : str.toCharArray()) {
if (Character.isUpperCase(c)) {
count++;
}
}
Your pattern as you've written it looks for 1 or more capital letters between the beginning and the end of the line...if there are any lowercase characters in the line it won't match.
In this example i'm using a regex(regular Expression) to count the number of UpperCase and LowerCase letters in the given string using Java.
import java.util.regex.*;
import java.util.Scanner;
import java.io.*;
public class CandidateCode {
public static void main(String args[] ) throws Exception {
Scanner sc= new Scanner(System.in);
// Reads the String of data entered in a line
String str = sc.nextLine();
//counts uppercase letteres in the given String
int countuc = str.split("([A-Z]+?)").length;
//counts lowercase letteres in the given String
int countlc = str.split("([a-z]+?)").length;
System.out.println("UpperCase count: "+countuc-1);
System.out.println("LowerCase count: "+countlc-1);
}
}
Change the regular expression to
[A-Z] which checks all occurrences of capital letters
Please refer the below example which counts number of capital letters in a string using pattern
#Test
public void testCountTheNumberOfUpperCaseCharacters() {
Pattern ptrn = Pattern.compile("[A-Z]");
Matcher matcher = ptrn.matcher("ivekKVVV");
int from = 0;
int count = 0;
while(matcher.find(from)) {
count++;
from = matcher.start() + 1;
}
System.out.println(count);
}
}
You can also use Java Regex, for example:
.+[\p{javaUpperCase}].+
An example from my work project:
Here's a solution for Java 9 and later that makes use of the results() method of Matcher, which returns a stream of the results, out of which the entries can be counted. The suggestion from #Sergey Kalinichenko to remove the ^ and $ anchors has also been incorporated into the regex string.
public class RegEx {
#Test
public void testCountTheNumberOfUpperCaseCharacters() {
String testStr = "abcdefghijkTYYtyyQ";
String regEx = "\\p{Lu}";
Pattern pattern = Pattern.compile(regEx);
Matcher matcher = pattern.matcher(testStr);
long count = matcher.results().count();
System.out.printf("Found %d of capital letters in %s%n", count, testStr);
}
}
I have the following string:
"hello this.is.a.test(MainActivity.java:47)"
and I want to be able to extract the MainActivity.java:47
(everything that is inside '(' and ')' and only the first occurance).
I tried with regex but it seems that I am doing something wrong.
Thanks
You can do it yourself:
int pos1 = str.indexOf('(') + 1;
int pos2 = str.indexOf(')', pos1);
String result = str.substring(pos1, pos2)
Or you can use commons-lang which contains a very nice StringUtils class that has substringBetween()
I think Regex is a liitle bit an overkill. I would use something like this:
String input = "hello this.is.a.test(MainActivity.java:47)";
String output = input.subString(input.lastIndexOf("(") + 1, input.lastIndexOf(")"));
This should work:
^[^\\(]*\\(([^\\)]+)\\)
The result is in the first group.
Another answer for your question :
String str = "hello this.is.a.test(MainActivity.java:47) another.test(MyClass.java:12)";
Pattern p = Pattern.compile("[a-z][\\w]+\\.java:\\d+", Pattern.CASE_INSENSITIVE);
Matcher m=p.matcher(str);
if(m.find()) {
System.out.println(m.group());
}
The RegExp explained :
[a-z][\w]+\.java:\d+
[a-z] > Check that we start with a letter ...
[\w]+ > ... followed by a letter, a digit or an underscore...
\.java: > ... followed exactly by the string ".java:"...
\d+ > ... ending by one or more digit(s)
Pseudo-code:
int p1 = location of '('
int p2 = location of ')', starting the search from p1
String s = extract string from p1 to p2
String.indexOf() and String.substring() are your friends.
Try this:
String input = "hello this.is.a.test(MainActivity.java:47) (and some more text)";
Pattern p = Pattern.compile("[^\\)]*\\(([^\\)]*)\\).*");
Matcher m = p.matcher( input );
if(m.matches()) {
System.out.println(m.group( 1 )); //output: MainActivity.java:47
}
This also finds the first occurence of text between ( and ) if there are more of them.
Note that in Java you normally have the expressions wrapped with ^ and $ implicitly (or at least the same effect), i.e. the regex must match the entire input string. Thus [^\\)]* at the beginning and .* at the end are necessary.
i need to extract the numbers alone from this text i use sub string to extract the details some times the number decreases so i am getting an error value...
example(16656);
Use Pattern to compile your regular expression and Matcher to get a particular captured group. The regex I'm using is:
example\((\d+)\)
which captures the digits (\d+) within the parentheses. So:
Pattern p = Pattern.compile("example\\((\\d+)\\)");
Matcher m = p.matcher(text);
if (m.find()) {
int i = Integer.valueOf(m.group(1));
...
}
look at Java Regular Expression sample here:
http://java.sun.com/developer/technicalArticles/releases/1.4regex/
specially focus on find method.
String yourString = "example(16656);";
Pattern pattern = Pattern.compile("\\w+\\((\\d+)\\);");
Matcher matcher = pattern.matcher(yourString);
if (matcher.matches())
{
int value = Integer.parseInt(matcher.group(1));
System.out.println("Your number: " + value);
}
I will suggest you to write your own logic to do this. Using Pattern and Matcher things from java are good practice but these are standard solutions and may not suit as a solution in effective manner always. Like cletus provided a very neat solution but what happens in this logic is that a substring matching algorithm is performed in the background to trace digits. You do not need the pattern finding here I suppose. You just need to extract the digits from a string (like 123 from "a1b2c3") .See the following code which does it in clean manner in O(n) and does not perform unnecessary extra operation as Pattern and Matcher classes do for you (just do copy and paste and run :) ):
public class DigitExtractor {
/**
* #param args
*/
public static void main(String[] args) {
String sample = "sdhj12jhj345jhh6mk7mkl8mlkmlk9knkn0";
String digits = getDigits(sample);
System.out.println(digits);
}
private static String getDigits(String sample) {
StringBuilder out = new StringBuilder(10);
int stringLength = sample.length();
for(int i = 0; i <stringLength ; i++)
{
char currentChar = sample.charAt(i);
int charDiff = currentChar -'0';
boolean isDigit = ((9-charDiff)>=0&& (9-charDiff <=9));
if(isDigit)
out.append(currentChar);
}
return out.toString();
}
}