Regex expression w/ set length - java

I have several thousands of rows that I'm loading into a database utilizing Pentaho. I must keep the string value length at 4 characters. The source file may only have a single character but it is still needed to keep the length at 4 characters to maintain consistency in the database.
Example:
Source: 10
Database expected results: 0010
I'm using a replace in string transformation or could use a java expression, which ever one works. Please help and provide a resolution utilizing either method (Regex or Javascript expression).
Thanks,

In Java you can use String.format(...) with a format specifier to pad your number with zeroes to 4 digits:
String.format("%04d", yournumber);
In Javascript you can use sprintf(...) for the same task:
var s = sprintf("%04d", yournumber);
So apparently sprintf() isn't standard Javascript but is a library you can download if you like. You can always to do this to get your 4 digits though:
// take the last 4 digits from the right
var s = String("0000" + yournumber).slice(-4);
And you could actually turn this into a simple left-padding function:
String.prototype.leftPad = function(paddingValue, paddingLength) {
return (new Array(paddingLength + 1).join(paddingValue) + this).slice(-paddingLength);
};
var s = String(yournumber).leftPad("0", 4)

(If you mean Javascript):
var str = "10";
function padIt(s) {
s = ""+s;
while (s.length < 4) {
s = "0" + s;
}
return s;
}
console.log(padIt(str));
http://jsfiddle.net/EzqRM/1/

For arbitrary padding of numbers, in javascript:
// padLeft(
// number to pad
// length to pad to
// character to pad with[optional, uses 0's if not specified]
// )
function padLeft(num, pad, padchr) {
num = "" + num;
pad = (pad || num.length) + 1;
return (num.length < pad ? new Array(pad - num.length).join(padchr || "0") : "") + num;
}
// returns "0010"
var input = 10
padded = padLeft(input, 4)

Related

Java Round decimal - specific case second decimal Zero

Given this numbers:
150.00
150.26
I need to round like this:
If the second value of decimal part is zero (0), then the new value should be 150.0
If the second value of decimal part is different than zero (0), then the new value keeps both decimals Ex.: 150.26
Is there a rounding method that can do this?
Thanks.
My code here:
String monto = "150.10";//150.26
String nuevoMonto = "";
String[] valores = monto.split("\\.");
System.out.println("Valores : " + valores);
System.out.println("Valores length: " + valores.length);
for (int i = 0; i < valores.length; i++) {
System.out.println("-->Valor: " + valores[i]);
}
if (valores.length == 2) {
nuevoMonto = valores[1];
System.out.println("Nuevomonto: " + nuevoMonto);
if (nuevoMonto.length() == 2) {
System.out.println("Dos posiciones decimales");
System.out.println(nuevoMonto.indexOf("0"));
if (nuevoMonto.indexOf("0") == 1) {
nuevoMonto = valores[0] + "." + nuevoMonto.substring(0, 1);
}
}
}
System.out.println("Nuevo monto: " + nuevoMonto);
try something like this:
DecimalFormat decimalFormat = new DecimalFormat("#.0#");
System.out.println(decimalFormat.format(150.09));
System.out.println(decimalFormat.format(150.10));
The string inside the new decimal format allows #s to be trimmed, and 0s are forced to stay
If you have a string to start with, perhaps there is no point parsing it to a floating point number and then reformatting it. Another approach is to use a regexp for this:
String monto = "150.10";
String nuevoMonto = monto.replaceAll("(?<=\\.\\d)0$", "")
The regexp consist of two parts. The first part (?<=\\.\\d) says the match need to be preceded by a dot and a digit. The second part 0$ matches the trailing zero at the end of the string. We replace it with nothing.
There is an expression in Java called floor method which can be used to always bring a value with any form of rounding to an integer value with any relevant decimal points removed from the data
a simple check for this wold be to take the data and check if the data is not modulo or mod of a zero
sample code might look like this.
if ((monto % 0.1 ) == 0)
{
//has no relevant data so it should be floored
Nuevomonto = floor (monto);
}
else
{
Nuevomonto = monto;
}
hope that helps.

Get last character of korean word in java

I am trying to get the last character of a Korean word (a String) but it's not working as planned. If I have the string: "사람", I want to get the "ㅁ" but I am getting the "람".
What I already have tried:
word.charAt(word.length-1); // gets 람
I have also checked if "사람" ends with "ㅁ" using word.endsWith("ㅁ"), but it returned false.
It gives true back if I ask, word.endsWith("람").
This answer uses information from How to convert to Korean initials and The Korean Writing System. As the latter one describes, the Hangul is divided into (possible) three parts: initial, vowel, and tail consonant (if present). The tail consonant may consist of 2 consonants like ㅆ.
The unicode coding was, IMHO, quite brilliantly designed so that the Hangul character coding can be encoded/decoded using a formula, as described by (The Korean Writing System) as:
tail = mod ($hangulCodepoint − 44032, 28)
vowel = 1 + mod ($hangulCodepoint − 44032 − tail, 588) / 28
lead = 1 + int [ ($hangulCodepoint − 44032) / 588 ]
Since I need the same thing as you describe, I implemented the following:
private final static String getCharacter(final String character) {
// the following characters are in the correct (i.e. Unicode) order
final String initials = "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ";// list of initials
final String vowels = "ᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵ";// list of vowels
final String finals = "ᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀᇁᇂ";// list of tail characters
final int characterValue = character.codePointAt(0); // Unicode value
final int hangulUnicodeStartValue = 44032;
if (characterValue < hangulUnicodeStartValue)
return character; // for instance for 32 (space)
final int tailIndex = Math.round((characterValue - hangulUnicodeStartValue) % 28) - 1;
final int vowelIndex = Math.round(((characterValue - hangulUnicodeStartValue - tailIndex) % 588) / 28);
final int initialIndex = (characterValue - hangulUnicodeStartValue) / 588;
final String leadString = initials.substring(initialIndex, initialIndex + 1);
final String vowelString = vowels.substring(vowelIndex, vowelIndex + 1);
final String tailString = tailIndex == -1 ? "" : finals.substring(tailIndex, tailIndex + 1);// may be -1 when there is no tail character
return leadString + vowelString + tailString;
}
Note that ㅎ (from the initials) is not the same as ᇂ (from tails) as is for all initials vs tails.
Note also that, due to index starting at 0 instead of 1 as the example from The Korean Writing System, we have to subtract 1 from tail and not add 1 for vowel and lead
To test the above code, you can use, for instance, which contains two three and four character values:
#Test
public void deconstructKoreanCharacters() {
final String koreanText = "항성은 항상 혼자 있는 것이 아니라, 두 개 이상의";
for (int i = 0; i < koreanText.length(); i++) {
final String character = koreanText.substring(i, i + 1);
final String decomposedCharacters = getCharacter(character);
System.out.println(character + ":" + decomposedCharacters);
}
Statics.doNothing();
}
If you need both characters from ᆪ, thus ㄱ and ㅅ this might be a bit manual work, as the number of possible tail characters is 27 (including single character tails)

Java automatic filling of ArrayList, searching for better options

I'm using this code here to automatically fill a string array list with the directory path of obj files for later use in animations, but there's a small problem with this:
private List<String> bunny_WalkCycle = new ArrayList<String>();
private int bunny_getWalkFrame = 0;
private void prepare_Bunny_WalkCycle() {
String bunny_walkFrame = "/bunnyAnimation/bunnyFrame0.obj";
while(bunny_WalkCycle.size() != 30) { // 30 obj files to loop through
if(bunny_getWalkFrame != 0) {
bunny_walkFrame =
"/bunnyAnimation/bunnyWalkAnim/bunnyWalkFrame_"+bunny_getWalkFrame+".obj";
}
bunny_WalkCycle.add(bunny_getWalkFrame);
bunny_getWalkFrame++;
}
}
Now the problem is that the naming convention in blender for animations has zeros before the actual numbers, so something like this:
bunnyWalkFrame_000001.obj
bunnyWalkFrame_000002.obj
bunnyWalkFrame_000003.obj
...
bunnyWalkFrame_000030.obj
With my prepare_Bunny_WalkCycle method I cannot account for the zeros so I would change the names and get rid of the zeros.. This may be okay for not so many frames but once I hit 100 frames it would get painfull.. So there's my question:
What would be an intelligent way to account for the zeros in the code instead of having to rename every file manually and remove them?
I think you can solve your problem with "String.format":
String blenderNumber = String.format("%06d", bunny_getWalkFrame);
Explanation:
0 -> to put leading zeros
6 -> "width" of them / amount of them
And so this would be your new bunny_walkFrame:
bunny_walkFrame = "/bunnyAnimation/bunnyWalkAnim/bunnyWalkFrame_" + blenderNumber + ".obj";
You can use String.format() to pad your numbers with zeros:
String.format("%05d", yournumber);
Here are two options. First, you can use a string formatter to create your filenames with leading zeros:
bunny_WalkCycle.add("/bunnyAnimation/bunnyFrame0.obj");
for (int frame = 1; frame <= 30; frame++) {
bunny_WalkCycle.add(
String.format("/bunnyAnimation/bunnyWalkAnim/bunnyWalkFrame_%06s.obj", frame));
}
The second option is, if you already have all the required files in the directory, you can get them all in one go:
bunny_WalkCycle.add("/bunnyAnimation/bunnyFrame0.obj");
bunny_WalkCycle.addAll(Arrays.asList(new File("/bunnyAnimation/bunnyWalkAnim").list()));
There are two ways you could do that:
Appending the right number of leading zeroes, or using a String formatter.
bunny_walkFrame = "/bunnyAnimation/bunnyWalkAnim/bunnyWalkFrame_" + String.format("%05d", bunny_getWalkFrame) + ".obj";
OR
bunny_walkFrame = "/bunnyAnimation/bunnyWalkAnim/bunnyWalkFrame_" + getLeadingZeroes(bunny_getWalkFrame) + String.valueOf(bunny_getWalkFrame) + ".obj";
where
private String getLeadingZeroes(int walk) {
String zeroes = "";
int countDigits = 0;
while (walk > 0) {
countDigits++;
walk /= 10;
}
for (int i = 1; i <= (nZeroes - countDigits); i++) {
zeroes += "0";
}
return zeroes;
}
Here ya go:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html
Just specify how many digits you want. Set it to one. If it has to it will push over (so it won't cut digits off)

Convert middle substring to "*"

I have a string String email="rachitgulati26#gmail.com" so its length is 24.
I want result like rachit************il.com.That means 1/4 of initial same and last 1/4 same.
Just want to convert 1/2 from middle to * with the help of regEX.
Thanks
You could do something like this:
"rachitgulati26#gmail.com".replaceAll("(?<=.{5}).(?=.{5})", "*");
this will replace all characters to * apart from the first and last 5.
In response to your question, you could make this flexible like this:
String email = "rachitgulati26#gmail.com";
int i = email.length() / 4;
email = email.replaceAll("(?<=.{" + i + "}).(?=.{" + i + "})", "*");
Just a word of warning, if you were to start using this in production code, you probably want to create a way of caching these regexes, based on the value of i. This way is for demonstration of the pattern only, and will compile a regex Pattern each time it is used.
One way to do it is to create a string of '*'s that is the correct length, then concatenate on the surrounding parts of the original string. That way you don't have to do any looping:
public static String starize(String str){
char[] middle = new char[str.length()/2];
Arrays.fill(middle, '*');
return str.substring(0, str.length()/4)
+ String.copyValueOf(middle)
+ str.substring(3 * str.length() / 4);
}
You could convert to char array, process and convert back to String:
String email = "rachitgulati26#gmail.com";
char[] a = email.toCharArray();
for (int i = 0, j = a.length >> 2; i < a.length >> 1; i++, j++)
a[j] = '*';
email = new String(a);
Result:
rachit************il.com
You can't identify the middle of a string using a single regular expression unless the lengths have a finite number of values.

Remove trailing zero in Java

I have Strings (from DB), which may contain numeric values. If it contains numeric values, I'd like to remove trailing zeros such as:
10.0000
10.234000
str.replaceAll("\\.0*$", ""), works on the first one, but not the second one.
A lot of the answers point to use BigDecimal, but the String I get may not be numeric. So I think a better solution probably is through the Regex.
there are possibilities:
1000 -> 1000
10.000 -> 10 (without point in result)
10.0100 -> 10.01
10.1234 -> 10.1234
I am lazy and stupid, just
s = s.indexOf(".") < 0 ? s : s.replaceAll("0*$", "").replaceAll("\\.$", "");
Same solution using contains instead of indexOf as mentioned in some of the comments for easy understanding
s = s.contains(".") ? s.replaceAll("0*$","").replaceAll("\\.$","") : s
Use DecimalFormat, its cleanest way
String s = "10.1200";
DecimalFormat decimalFormat = new DecimalFormat("0.#####");
String result = decimalFormat.format(Double.valueOf(s));
System.out.println(result);
Kent's string manipulation answer magically works and also caters for precision loss, But here's a cleaner solution using BigDecimal
String value = "10.234000";
BigDecimal stripedVal = new BigDecimal(value).stripTrailingZeros();
You can then convert to other types
String stringValue = stripedVal.toPlainString();
double doubleValue = stripedVal.doubleValue();
long longValue = stripedVal.longValue();
If precision loss is an ultimate concern for you, then obtain the exact primitive value. This would throw ArithmeticException if there'll be any precision loss for the primitive. See below
int intValue = stripedVal.intValueExact();
String value = "10.010"
String s = new DecimalFormat("0.####").format(Double.parseDouble(value));
System.out.println(s);
Output:
10.01
I find all the other solution too complicated. Simply
s.replaceFirst("\\.0*$|(\\.\\d*?)0+$", "$1");
does the job. It tries the first alternative first, so that dot followed by all zeros gets replaced by nothing (as the group doesn't get set). Otherwise, if it finds a dot followed by some digits (as few as possible due to the lazy quantifier *?) followed by some zeros, the zeros get discarded as they're not included in the group. It works.
Warning
My code relies on my assumption that appending a unmatched group does nothing. This is true for the Oracle implementation, but not for others, including Android, which seem to append the string "null". I'd call the such implementations broken as it just may no sense, but they're correct according to the Javadoc.
The following works for all the following examples:
"1" -> "1"
"1.0" -> "1"
"1.01500" -> "1.015"
"1.103" -> "1.103"
s = s.replaceAll("()\\.0+$|(\\..+?)0+$", "$2");
What about replacing
(\d*\.\d*)0*$
by
\1
?
You could replace with:
String result = (str.indexOf(".")>=0?str.replaceAll("\\.?0+$",""):str);
To keep the Regex as simple as possible. (And account for inputs like 1000 as pointed out in comments)
My implementation with possibility to select numbers of digits after divider:
public static String removeTrailingZero(String number, int minPrecise, char divider) {
int dividerIndex = number.indexOf(divider);
if (dividerIndex == -1) {
return number;
}
int removeCount = 0;
for (int i = dividerIndex + 1; i < number.length(); i++) {
if (number.charAt(i) == '0') {
removeCount++;
} else {
removeCount = 0;
}
}
int fracLen = number.length() - dividerIndex - 1;
if (fracLen - removeCount < minPrecise) {
removeCount = fracLen - minPrecise;
}
if (removeCount < 0) {
return number;
}
String result = number.substring(0, number.length() - removeCount);
if (result.endsWith(String.valueOf(divider))) {
return result.substring(0, result.length() - 1);
}
return result;
}
In addition to Kent's answer.
Be careful with regex in Kotlin. You have to manually write Regex() constructor instead of a simple string!
s = if (s.contains("."))
s.replace(Regex("0*\$"),"").replace(Regex("\\.\$"),"")
else s
Try to use this code:
DecimalFormat df = new DecimalFormat("#0.#####");
String value1 = df.format(101.00000);
String value2 = df.format(102.02000);
String value3 = df.format(103.20000);
String value4 = df.format(104.30020);
Output:
101
102.02
103.2
104.3002
Separate out the fraction part first. Then you can use the below logic.
BigDecimal value = BigDecimal.valueOf(345000);
BigDecimal div = new BigDecimal(10).pow(Integer.numberOfTrailingZeros(value.intValue()));
System.out.println(value.divide(div).intValue());

Categories