Skip to content

Instantly share code, notes, and snippets.

@L-Briand
Created February 5, 2024 09:55
Show Gist options
  • Save L-Briand/f996a213b55015179ea5d30be7036d8c to your computer and use it in GitHub Desktop.
Save L-Briand/f996a213b55015179ea5d30be7036d8c to your computer and use it in GitHub Desktop.
Read lines as sequence from the given stream or reader.
/**
* Read the [InputStream] and yield a [CharSequence] every time a new line is found.
*
* @receiver The [InputStream] to parse.
* @return a sequence of each line in the stream. (without new lines)
*/
fun InputStream.lineSequence(): Sequence<CharSequence> = lineSequence { read() }
fun Reader.lineSequence(): Sequence<CharSequence> = lineSequence { read() }
/**
* Returns a sequence of lines parsed from the [characterProvider].
*
* @param characterProvider A function that provides characters in the stream as integers.
* @return A sequence of String without new line.
*/
private fun lineSequence(characterProvider: () -> Int) = sequence {
val buffer = StringBuilder()
var peek: Int? = null
fun peek(): Int {
if (peek != null) return peek!!
peek = characterProvider()
return peek!!
}
fun consume() {
peek = null
}
fun next() = peek().also { consume() }
while (true) {
val current = next()
if (current == -1) break
when (val char = current.toChar()) {
'\n' -> {
yield(buffer.toString())
buffer.clear()
}
'\r' -> {
if (peek().toChar() == '\n') consume()
yield(buffer.toString())
buffer.clear()
}
else -> buffer.append(char)
}
}
yield(buffer.toString())
buffer.clear()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment