Skip to content

Conversation

@andrykonchin
Copy link
Contributor

Changes:

  • added remove_empty parameter for method def each_line(chomp : Bool = true, & : String ->) : Nil
  • added remove_empty parameter for method def each_line(chomp = true)

Closes #15149

@andrykonchin
Copy link
Contributor Author

andrykonchin commented Oct 18, 2025

I am concerned about handling "\n" lines when given chomp: false, so a line is logically "empty" but a String object returned to a user is not.

@ysbaddaden
Copy link
Contributor

The line itself is still empty?

Copy link
Member

@straight-shoota straight-shoota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove_empty applies a filter, chomp defines how the items are presented.
The empty line filter should not be affected by whether non-empty lines end with a NL character or not.

@andrykonchin
Copy link
Contributor Author

The line itself is still empty?

Confusion that may happen is what is filtered with the remove_empty filter - lines or strings as far as "\n" is a non-empty string but an empty line.

It seems logical to apply the filter to lines, that's a "\n" line will be filtered out regardless of the chomp option value. Does is make sense?

src/string.cr Outdated
Comment on lines 4418 to 4427
if remove_empty
line_length = count - 1
if offset + line_length > 0 && to_unsafe[offset + line_length - 1] === '\r'
line_length -= 1
end

skip_line = line_length == 0
else
skip_line = false
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: This logic seems a bit convoluted.
The empty line detection can be simplified to byte_index == offset || (byte_index == offset + 1 && to_unsafe[byte_index - 1] === '\r').

Also, the loop might be a bit better readable if directly skip to the next iteration with next.

Suggested change
if remove_empty
line_length = count - 1
if offset + line_length > 0 && to_unsafe[offset + line_length - 1] === '\r'
line_length -= 1
end
skip_line = line_length == 0
else
skip_line = false
end
if remove_empty && (byte_index == offset || (byte_index == offset + 1 && to_unsafe[byte_index - 1] === '\r'))
offset = byte_index + 1
next
end

Ditto for the iterator. There we can return early with self.next.

Copy link
Contributor Author

@andrykonchin andrykonchin Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you! Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove empty lines from String#each_line

3 participants