I'm trying to generate a md5 hash in Kotlin using the DigestUtils class from the org.apache.commons.codec. Here's the test code
#Test
fun md5Test(){
val userPassword: String = "123"
val md5Hash: String = "202cb962ac59075b964b07152d234b70"
assertEquals(md5Hash, DigestUtils.md5Hex(userPassword))
}
The problem is that when I run this test it fails and says that the generated md5 hash is 28c1a138574866e9c2e5a19dca9234ce
But... when I pass the String value instead of the object
assertEquals(md5Hash, DigestUtils.md5Hex("123"))
The test passes without errors
Why this is happening?
Here is a complete solution to get MD5 base64 hash:
fun getMd5Base64(encTarget: ByteArray): String? {
val mdEnc: MessageDigest?
try {
mdEnc = MessageDigest.getInstance("MD5")
// Encryption algorithmy
val md5Base16 = BigInteger(1, mdEnc.digest(encTarget)) // calculate md5 hash
return Base64.encodeToString(md5Base16.toByteArray(), 16).trim() // convert from base16 to base64 and remove the new line character
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
return null
}
}
This is the most simple and complete solution in kotlin:
val hashedStr = String.format("%032x", BigInteger(1, MessageDigest.getInstance("MD5").digest("your string value".toByteArray(Charsets.UTF_8))))
Related
I'm new to Kotlin (I have a Java background) and I can't seem to figure out how to check whether a string contains a match from a list of keywords.
What I want to do is check if a string contains a match from an array of keywords (case-insensitive please). If so, print out the keyword(s) that was matched and the string that contained the keyword. (I will be looping over a bunch of strings in a file).
Here's an MVE for starters:
val keywords = arrayOf("foo", "bar", "spam")
fun search(content: String) {
var match = <return an array of the keywords that content contained>
if(match.size > 0) {
println("Found match(es): " + match + "\n" + content)
}
}
fun main(args: Array<String>) {
var str = "I found food in the barn"
search(str) //should print out that foo and bar were a match
}
As a start (this ignores the 'match' variable and getting-a-list-of-keywords-matched), I tried using the following if statement according with what I found at this question,
if(Arrays.stream(keywords).parallel().anyMatch(content::contains))
but it put a squiggly line under "content" and gave me this error
None of the following functions can be called with the arguments
supplied: public operator fun CharSequence.contains(char: Char,
ignoreCase: Boolean = ...): Boolean defined in kotlin.text public
operator fun CharSequence.contains(other: CharSequence, ignoreCase:
Boolean = ...): Boolean defined in kotlin.text #InlineOnly public
inline operator fun CharSequence.contains(regex: Regex): Boolean
defined in kotlin.text
You can use the filter function to leave only those keywords contained in content:
val match = keywords.filter { it in content }
Here match is a List<String>. If you want to get an array in the result, you can add .toTypedArray() call.
in operator in the expression it in content is the same as content.contains(it).
If you want to have case insensitive match, you need to specify ignoreCase parameter when calling contains:
val match = keywords.filter { content.contains(it, ignoreCase = true) }
Another obvious choice is using a regex doing case-insensitive matching:
arrayOf("foo", "bar", "spam").joinToString(prefix = "(?i)", separator = "|").toRegex())
Glues together a pattern with a prefixed inline (?i) incase-sensitive modifier, and alternations between the keywords: (?i)foo|bar|spam
Sample Code:
private val keywords = arrayOf("foo", "bar", "spam")
private val pattern = keywords.joinToString(prefix = "(?i)", separator = "|")
private val rx = pattern.toRegex()
fun findKeyword(content: String): ArrayList<String> {
var result = ArrayList<String>()
rx.findAll(content).forEach { result.add(it.value) }
return result
}
fun main(args: Array<String>) {
println(findKeyword("Some spam and a lot of bar"));
}
The regex approach could be handy if you are after some more complex matching, e.g. non-/overlapping matches adding word boundaries \b, etc.
Here is my approach without Streams:
fun String.containsAnyOfIgnoreCase(keywords: List<String>): Boolean {
for (keyword in keywords) {
if (this.contains(keyword, true)) return true
}
return false
}
Usage:
"test string".containsAnyOfIgnoreCase(listOf("abc","test"))
I think Any is the efficient way.
fun findMatch(s: String, strings: List<String>): Boolean {
return strings.any { s.contains(it) }
}
fun main() {
val today = "Wednesday"
val weekend = listOf("Sat", "Sun")
println(if (findMatch(today, weekend)) "Yes" else "No") // No
}
reference: click here
If have an Array and want to convert it to a ByteArray, how should I go about it? The following for instance fails:
var srcArray = Array<Byte>(10, { 0 })
var tgtArray: ByteArray = srcArray as ByteArray
I do realize though that specialized classes such as ByteArray are:
... not related to the Array class and are compiled down to Java’s primitive arrays for maximum performance.
So, the fact that my approach fails shouldn't surprise me - but what is the canonical way to make the conversion? Simply iterate through srcArray and populate tgtArray one index at a time - or is there a more elegant solution I'm missing?
I don't see any built-in functions apart from the obvious loop-based approach. But you could define an extension function like this yourself:
fun Array<Byte>.toPrimitive(): ByteArray {
val tgtArray: ByteArray = ByteArray(this.size())
for (i in this.indices) {
tgtArray[i] = this[i]
}
return tgtArray
}
fun test() {
val srcArray = Array<Byte>(10, { 0 })
val tgtArray: ByteArray = srcArray.toPrimitive()
}
Kotlin has this in the stdlib as an extension function Array<Byte>.toByteArray()
val srcArray = Array<Byte>(10, { 0 })
val tgtArray = srcArray.toByteArray()
(Note: I changed your var to val which is more common in Kotlin to use read-only values)
You will see similar ones for other primitive data types that have array implementations. You can see them all in the Kotlin documentation for Array extension functions.
I read into myArray (native Swift) from a file containing a few thousand lines of plain text..
myData = String.stringWithContentsOfFile(myPath, encoding: NSUTF8StringEncoding, error: nil)
var myArray = myData.componentsSeparatedByString("\n")
I change some of the text in myArray (no point pasting any of this code).
Now I want to write the updated contents of myArray to a new file.
I've tried this ..
let myArray2 = myArray as NSArray
myArray2.writeToFile(myPath, atomically: false)
but the file content is then in the plist format.
Is there any way to write an array of text strings to a file (or loop through an array and append each array item to a file) in Swift (or bridged Swift)?
As drewag points out in the accepted post, you can build a string from the array and then use the writeToFile method on the string.
However, you can simply use Swift's Array.joinWithSeparator to accomplish the same with less code and likely better performance.
For example:
// swift 2.0
let array = [ "hello", "goodbye" ]
let joined = array.joinWithSeparator("\n")
do {
try joined.writeToFile(saveToPath, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
// handle error
}
// swift 1.x
let array = [ "hello", "goodbye" ]
let joined = "\n".join(array)
joined.writeToFile(...)
With Swift 5 and I guess with Swift 4 you can use code snippet which works fine to me.
let array = ["hello", "world"]
let joinedStrings = array.joined(separator: "\n")
do {
try joinedStrings.write(toFile: outputURL.path, atomically: true, encoding: .utf8)
} catch let error {
// handle error
print("Error on writing strings to file: \(error)")
}
You need to reduce your array back down to a string:
var output = reduce(array, "") { (existing, toAppend) in
if existing.isEmpty {
return toAppend
}
else {
return "\(existing)\n\(toAppend)"
}
}
output.writeToFile(...)
The reduce method takes a collection and merges it all into a single instance. It takes an initial instance and closure to merge all elements of the collection into that original instance.
My example takes an empty string as its initial instance. The closure then checks if the existing output is empty. If it is, it only has to return the text to append, otherwise, it uses String Interpolation to return the existing output and the new element with a newline in between.
Using various syntactic sugar features from Swift, the whole reduction can be reduced to:
var output = reduce(array, "") { $0.isEmpty ? $1 : "\($0)\n\($1)" }
Swift offers numerous ways to loop through an array. You can loop through the strings and print to a text file one by one. Something like so:
for theString in myArray {
theString.writeToFile(myPath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
}
I am trying converting java to perl (md5)program.
How can i do following two programs same output MD5 sum.
Java
import java.security.MessageDigest;
import java.math.BigInteger;
public class Hash
{
public static void main( String[] args ) throws Exception
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
String plain = "abcd1234";
BigInteger digest = new BigInteger(md5.digest(plain.getBytes("UTF-8")));
System.out.println( digest.abs() );
}
}
Perl
use Digest::MD5 'md5_hex';
use Math::BigInt;
my $plain = "abcd1234";
my $digest = Math::BigInt::->from_hex(md5_hex $plain);
print $digest, "\n";
I Think,
Java:
BigInteger digest = new BigInteger(md5.digest(plain.getBytes("UTF-8")));
Perl:
my $digest = Math::BigInt::->from_hex(md5_hex $plain);
here is diffrent output MD5 sum.
I want to edit perl source.
Your BigInteger() call requires a byte array containing the two's complement binary representation of the number. You need to use the sign-magnitude constructor:
public BigInteger(int signum, byte[] magnitude)
So, your Java code should be:
import java.security.MessageDigest;
import java.math.BigInteger;
public class Hash
{
public static void main(String[] args) throws Exception
{
MessageDigest md5 = MessageDigest.getInstance("MD5");
String plain = "abcd1234";
BigInteger digest = new BigInteger(1, md5.digest(plain.getBytes("UTF-8")));
System.out.println(digest.abs());
}
}
Your Perl code didn't quite work for me, either. My version of Math::BigInt requires a string representation of the hex value, like so:
use Digest::MD5 'md5_hex';
use Math::BigInt;
my $plain = "abcd1234";
my $digest = Math::BigInt::->from_hex('0x' . md5_hex($plain));
print $digest, "\n";
When I run those two commands, I get the same digest value displayed.
I have a file with content like this:
"Some","Words","separated","by","comma","and","quoted","with","double","quotes"
The File is to large to read it into just on String.
What is the simplest way to split it into a Traversable of Strings, with each element being a word?
If it matters: While the content of the file won't fit in a single String the resulting Traversable might be a List without a problem.
Here is an adaptation of your own solution, using JavaConversions to manipulate the Java iterator as a Scala one.
import java.util.Scanner
import java.io.File
import scala.collection.JavaConversions._
val scanner = new Scanner(new File("...")).useDelimiter(",")
scanner.map(_.trim).map(quoted => quoted.substring(1, quoted.length - 1))
This gives you an iterator. You can always convert it to a list using e.g. .toList.
Here is a version using stringLit and repsep from Scala parser combinators. I won't vouch for its efficiency, though.
import scala.util.parsing.combinator.syntactical.StdTokenParsers
import scala.util.parsing.combinator.lexical.StdLexical
import scala.util.parsing.input.StreamReader
import java.io.FileReader
object P extends StdTokenParsers {
type Tokens = StdLexical
val lexical = new StdLexical
lexical.delimiters += ","
def words : Parser[List[String]] = repsep(stringLit, ",")
def getWords(fileName : String) : List[String] = {
val scanner = new lexical.Scanner(StreamReader(new FileReader(fileName)))
// better error handling wouldn't hurt.
words(scanner).get
}
}
I did it using the java.util.Scanner while it does work, I'd appreciate a more scalaesc version.
val scanner = new Scanner(new File("""bigFile.txt""")).useDelimiter(",")
var wordList: Vector[String] = Vector()
while (scanner.hasNext()) {
val quoted = scanner.next()
val word = quoted.replace("\"", "")
wordList = wordList :+ word
}