String#byteslice
str.byteslice(index) or str.byteslice(start, length) String or nil · Added in v1.8.7 · Updated March 13, 2026 · String Methods The byteslice method extracts a portion of a string based on byte positions rather than character positions. This is essential when working with binary data, specific byte-level operations, or when you need precise control over multi-byte character encodings like UTF-8.
Unlike slice, which works with character indices, byteslice operates at the byte level. This distinction becomes critical when working with non-ASCII characters where a single character may occupy multiple bytes.
Syntax
str.byteslice(index) # Single byte position
str.byteslice(start, length) # Range of bytes
str.byteslice(range) # Byte range
Parameters
index— A zero-based byte position (Integer)start— The starting byte position (Integer)length— The number of bytes to extract (Integer)range— A Range of byte positions
Return Value
Returns a new string containing the extracted bytes, or nil if the index is out of bounds.
Examples
Basic byte extraction
ascii = "hello"
ascii.byteslice(0) # => "h"
ascii.byteslice(1) # => "e"
ascii.byteslice(-1) # => "o"
Extracting a byte range
"hello".byteslice(1, 3)
# => "ell"
"hello".byteslice(1..3)
# => "ell"
Working with multi-byte characters
When dealing with UTF-8 encoded strings, characters beyond ASCII occupy multiple bytes:
text = "こんにちは" # 5 characters, 15 bytes in UTF-8
text.byteslice(0) # Returns nil because first character starts at byte 0 but is 3 bytes long
text.byteslice(0, 3) # => "こ" - first 3 bytes form the first character
text.byteslice(3, 3) # => "ん" - bytes 3-5 form the second character
Comparing byteslice vs slice
text = "日本"
text.slice(0) # => "日" - character at position 0
text.byteslice(0) # => nil - cannot extract single byte from 3-byte character
text.slice(0, 1) # => "日" - 1 character
text.byteslice(0, 1) # => nil - returns nil for partial character
text.byteslice(0, 3) # => "日" - 3 bytes = 1 complete character
Common Use Cases
Extract bytes from binary data
data = "\xFF\xFE\x00\x01"
data.byteslice(0, 2) # => "\xFF\xFE"
data.byteslice(2, 2) # => "\x00\x01"
Parse byte-level protocols
def extract_header(bytes)
{
version: bytes.byteslice(0, 1).ord,
flags: bytes.byteslice(1, 1).ord,
length: bytes.byteslice(2, 2).unpack("n").first
}
end
Handle encoding edge cases
def truncate_to_bytes(str, max_bytes)
return "" if max_bytes <= 0
str.byteslice(0, max_bytes) || str
end
truncate_to_bytes("こんにちは", 6)
# => "こん" - cuts at byte boundary, not character
Error Handling
byteslice returns nil when the index is out of bounds, making it safe to use without raising errors:
"hi".byteslice(10) # => nil
"hi".byteslice(-10) # => nil
"".byteslice(0) # => nil
However, when using the two-argument form with invalid arguments, it still returns nil:
"hello".byteslice(0, -1) # => nil (negative length)
Performance
byteslice is efficient because it creates a new string from existing bytes without re-encoding:
text = "hello world"
text.byteslice(0, 5) # => "hello" - no re-encoding needed
See Also
- string::slice - Extracts a substring by character position
- string::bytesize - Returns the byte count of a string
- string::chars - Returns an array of characters