diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb
index e5a214f5a..d4f717dea 100644
--- a/mrbgems/mruby-string-ext/mrblib/string.rb
+++ b/mrbgems/mruby-string-ext/mrblib/string.rb
@@ -134,63 +134,8 @@ class String
self
end
- ##
- # call-seq:
- # str.ljust(integer, padstr=' ') -> new_str
- #
- # If integer is greater than the length of str, returns a new
- # String of length integer with str left justified
- # and padded with padstr; otherwise, returns str.
- #
- # "hello".ljust(4) #=> "hello"
- # "hello".ljust(20) #=> "hello "
- # "hello".ljust(20, '1234') #=> "hello123412341234123"
- def ljust(idx, padstr = ' ')
- raise ArgumentError, 'zero width padding' if padstr == ''
- return self if idx <= self.size
- pad_repetitions = idx / padstr.size
- padding = (padstr * pad_repetitions)[0, idx-self.size]
- self + padding
- end
- ##
- # call-seq:
- # str.rjust(integer, padstr=' ') -> new_str
- #
- # If integer is greater than the length of str, returns a new
- # String of length integer with str right justified
- # and padded with padstr; otherwise, returns str.
- #
- # "hello".rjust(4) #=> "hello"
- # "hello".rjust(20) #=> " hello"
- # "hello".rjust(20, '1234') #=> "123412341234123hello"
- def rjust(idx, padstr = ' ')
- raise ArgumentError, 'zero width padding' if padstr == ''
- return self if idx <= self.size
- pad_repetitions = idx / padstr.size
- padding = (padstr * pad_repetitions)[0, idx-self.size]
- padding + self
- end
- ##
- # call-seq:
- # str.center(width, padstr=' ') -> new_str
- #
- # Centers +str+ in +width+. If +width+ is greater than the length of +str+,
- # returns a new String of length +width+ with +str+ centered and padded with
- # +padstr+; otherwise, returns +str+.
- #
- # "hello".center(4) #=> "hello"
- # "hello".center(20) #=> " hello "
- # "hello".center(20, '123') #=> "1231231hello12312312"
- def center(width, padstr = ' ')
- raise ArgumentError, 'zero width padding' if padstr == ''
- return self if width <= self.size
- width -= self.size
- pad1 = width / 2
- pad2 = width - pad1
- (padstr*pad1)[0,pad1] + self + (padstr*pad2)[0,pad2]
- end
##
diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c
index 5fc9c66f0..78e3f39d3 100644
--- a/mrbgems/mruby-string-ext/src/string.c
+++ b/mrbgems/mruby-string-ext/src/string.c
@@ -1593,6 +1593,26 @@ str_strip_bang(mrb_state *mrb, mrb_value self)
return self;
}
+/* Count UTF-8 characters in a string using mruby's standard function */
+static mrb_int
+str_char_count(mrb_value str)
+{
+#ifdef MRB_UTF8_STRING
+ struct RString *s = mrb_str_ptr(str);
+
+ if (RSTR_SINGLE_BYTE_P(s) || RSTR_BINARY_P(s)) {
+ /* ASCII/Binary: each byte is a character */
+ return RSTR_LEN(s);
+ }
+
+ /* UTF-8: use mruby's standard UTF-8 character counting function */
+ return mrb_utf8_strlen(RSTR_PTR(s), RSTR_LEN(s));
+#else
+ /* Non-UTF8 build: treat as single bytes */
+ return RSTRING_LEN(str);
+#endif
+}
+
/* internal fast path for String#chars */
static mrb_value
str_chars_ary(mrb_state *mrb, mrb_value self)
@@ -1656,6 +1676,173 @@ str_chars_ary(mrb_state *mrb, mrb_value self)
return result;
}
+/*
+ * call-seq:
+ * str.ljust(integer, padstr=' ') -> new_str
+ *
+ * If integer is greater than the length of str, returns a new
+ * String of length integer with str left justified and padded with padstr;
+ * otherwise, returns str.
+ */
+static mrb_value
+str_ljust_core(mrb_state *mrb, mrb_value self)
+{
+ mrb_int width;
+ mrb_value padstr = mrb_str_new_lit(mrb, " ");
+ mrb_int char_len, pad_char_len, padsize;
+
+ mrb_get_args(mrb, "i|S", &width, &padstr);
+
+ if (RSTRING_LEN(padstr) == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ char_len = str_char_count(self);
+ if (width <= char_len) {
+ return mrb_str_dup(mrb, self);
+ }
+
+ padsize = width - char_len;
+ pad_char_len = str_char_count(padstr);
+ if (pad_char_len == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ /* Build padding string by repeating padstr */
+ mrb_value padding = mrb_str_new_lit(mrb, "");
+ mrb_int chars_needed = padsize;
+ while (chars_needed > 0) {
+ if (chars_needed >= pad_char_len) {
+ mrb_str_cat_str(mrb, padding, padstr);
+ chars_needed -= pad_char_len;
+ } else {
+ /* Need partial padding - use substr to get exact characters */
+ mrb_value partial = mrb_str_substr(mrb, padstr, 0, chars_needed);
+ mrb_str_cat_str(mrb, padding, partial);
+ chars_needed = 0;
+ }
+ }
+
+ return mrb_str_cat_str(mrb, mrb_str_dup(mrb, self), padding);
+}
+
+/*
+ * call-seq:
+ * str.rjust(integer, padstr=' ') -> new_str
+ *
+ * If integer is greater than the length of str, returns a new
+ * String of length integer with str right justified and padded with padstr;
+ * otherwise, returns str.
+ */
+static mrb_value
+str_rjust_core(mrb_state *mrb, mrb_value self)
+{
+ mrb_int width;
+ mrb_value padstr = mrb_str_new_lit(mrb, " ");
+ mrb_int char_len, pad_char_len, padsize;
+
+ mrb_get_args(mrb, "i|S", &width, &padstr);
+
+ if (RSTRING_LEN(padstr) == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ char_len = str_char_count(self);
+ if (width <= char_len) {
+ return mrb_str_dup(mrb, self);
+ }
+
+ padsize = width - char_len;
+ pad_char_len = str_char_count(padstr);
+ if (pad_char_len == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ /* Build padding string by repeating padstr */
+ mrb_value padding = mrb_str_new_lit(mrb, "");
+ mrb_int chars_needed = padsize;
+ while (chars_needed > 0) {
+ if (chars_needed >= pad_char_len) {
+ mrb_str_cat_str(mrb, padding, padstr);
+ chars_needed -= pad_char_len;
+ } else {
+ /* Need partial padding - use substr to get exact characters */
+ mrb_value partial = mrb_str_substr(mrb, padstr, 0, chars_needed);
+ mrb_str_cat_str(mrb, padding, partial);
+ chars_needed = 0;
+ }
+ }
+
+ return mrb_str_cat_str(mrb, padding, self);
+}
+
+/*
+ * call-seq:
+ * str.center(width, padstr=' ') -> new_str
+ *
+ * Centers str in width. If width is greater than the length of str,
+ * returns a new String of length width with str centered and padded with
+ * padstr; otherwise, returns str.
+ */
+static mrb_value
+str_center_core(mrb_state *mrb, mrb_value self)
+{
+ mrb_int width;
+ mrb_value padstr = mrb_str_new_lit(mrb, " ");
+ mrb_int char_len, pad_char_len, total_pad, left_pad, right_pad;
+
+ mrb_get_args(mrb, "i|S", &width, &padstr);
+
+ if (RSTRING_LEN(padstr) == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ char_len = str_char_count(self);
+ if (width <= char_len) {
+ return mrb_str_dup(mrb, self);
+ }
+
+ total_pad = width - char_len;
+ left_pad = total_pad / 2;
+ right_pad = total_pad - left_pad;
+
+ pad_char_len = str_char_count(padstr);
+ if (pad_char_len == 0) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "zero width padding");
+ }
+
+ /* Build left padding */
+ mrb_value left_padding = mrb_str_new_lit(mrb, "");
+ mrb_int chars_needed = left_pad;
+ while (chars_needed > 0) {
+ if (chars_needed >= pad_char_len) {
+ mrb_str_cat_str(mrb, left_padding, padstr);
+ chars_needed -= pad_char_len;
+ } else {
+ mrb_value partial = mrb_str_substr(mrb, padstr, 0, chars_needed);
+ mrb_str_cat_str(mrb, left_padding, partial);
+ chars_needed = 0;
+ }
+ }
+
+ /* Build right padding */
+ mrb_value right_padding = mrb_str_new_lit(mrb, "");
+ chars_needed = right_pad;
+ while (chars_needed > 0) {
+ if (chars_needed >= pad_char_len) {
+ mrb_str_cat_str(mrb, right_padding, padstr);
+ chars_needed -= pad_char_len;
+ } else {
+ mrb_value partial = mrb_str_substr(mrb, padstr, 0, chars_needed);
+ mrb_str_cat_str(mrb, right_padding, partial);
+ chars_needed = 0;
+ }
+ }
+
+ mrb_value result = mrb_str_cat_str(mrb, left_padding, self);
+ return mrb_str_cat_str(mrb, result, right_padding);
+}
+
void
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
{
@@ -1711,6 +1898,11 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
/* Fast path for chars method implemented in C */
mrb_define_method_id(mrb, s, MRB_SYM(__chars), str_chars_ary, MRB_ARGS_NONE());
+ /* Padding methods implemented in C */
+ mrb_define_method_id(mrb, s, MRB_SYM(ljust), str_ljust_core, MRB_ARGS_ARG(1,1));
+ mrb_define_method_id(mrb, s, MRB_SYM(rjust), str_rjust_core, MRB_ARGS_ARG(1,1));
+ mrb_define_method_id(mrb, s, MRB_SYM(center), str_center_core, MRB_ARGS_ARG(1,1));
+
mrb_define_method_id(mrb, mrb->integer_class, MRB_SYM(chr), int_chr, MRB_ARGS_OPT(1));
}