I want to remove and replace all characters before a certain character in string. For example with "045723456789", i want that to become "+44723456789", by removing all characters before the "7" and replacing it with "+44", in ruby. I need to do this without any libraries eg, regex
-
Does this answer your question? [Ruby replace string with captured regex pattern](https://stackoverflow.com/questions/9898461/ruby-replace-string-with-captured-regex-pattern) – markalex Mar 26 '23 at 21:25
-
No, apologies i have updated the question. I need to do it without regex – b.herring Mar 26 '23 at 21:28
-
why no regex? if not, you will have to does this work for you? original_str = "045723456789" # find the index of the first occurrence of "7" in the string index_of_7 = original_str.index("7") and remove it or whatever – merof Mar 26 '23 at 21:52
-
The [Regexp](https://ruby-doc.org/3.2.1/Regexp.html) class is part of Ruby's core classes and is automagically included at runtime. You don't need to `require` it, as it's in core and not the Ruby Standard Library. Either way, what exactly does it mean to you to avoid "any libraries?" Both String and Regexp are core classes, and most things in Ruby are classes that have well-tuned methods for making easy jobs easy. `"045723456789".sub /^045/, "+44"` seems a whole lot easier if you already know what you want to replace. – Todd A. Jacobs Mar 27 '23 at 00:17
-
Oh, and `"045723456789".sub "045", "+44"` works too, with only String matching and no Regexp needed. But without regex anchors, `"+44" + "045723456789".delete_prefix("045")` might work better if there's a possible fixed-string match deeper inside the input value. – Todd A. Jacobs Mar 27 '23 at 00:23
-
"Without any libraries" is a lot different than "without non-core classes" or "without external gems." The first is just silly, IMHO. If you're excluding core classes, then you need to exclude String, too. If that's the case, what's the actual intent, and how would you do it without any descendant of Object? – Todd A. Jacobs Mar 27 '23 at 00:28
3 Answers
def remove_and_replace(str, ch, replace)
i = str.index(ch)
i.nil? ? nil : replace + str[i..]
end
remove_and_replace("045723456789", "7", "+44") #=> "+44723456789"
remove_and_replace("045123456789", "7", "+44") #=> "+44789"
remove_and_replace("045123456189", "7", "+44") #=> nil
See String#index and String#concat.

- 106,649
- 6
- 63
- 100
-
1@MichaelB, the only reason I used `concat` was to avoid the creation of another string, but adding strings is fine and perhaps reads better. – Cary Swoveland Mar 27 '23 at 05:26
-
1Modifying `str` would probably be okay according to the OP's requirements, but modifying the `replace` argument doesn't seem right. (imagine passing a variable instead of a literal) – Stefan Mar 27 '23 at 08:21
-
Preface
Homework assignments (which this seems like) that are arbitrarily constrained will either have an expected answer provided by your instructor—in which case, either re-read your course material or ask your instructor for guidance; that's what they're being paid for!—or the answer should be related to material you're studying and a suitable answer contained therein.
Absent some educational point to make, the constraint is just arbitrary. Even if you can do it in other ways, a regular expression is likely slower but more generalizable than other solutions. That said, you can certainly take other approaches to the problem.
Using String Methods
In Ruby, String methods are usually much faster than regular expressions, but are not the best fit for all use cases. In your case, a String#sub method would be simpler and more idiomatic, and can use strings instead of regular expressions for matching, but without a regex you have to work harder to isolate or anchor the text you want to replace. You can do what you want with various String methods that don't rely on regular expressions, but you still need to consider how reliable the assumption is that you can always just replace the first three characters with something else.
Missing Specifications
The hardest part of regex-free solutions lies in picking the optimal solution based on specifications you haven't provided, such as:
- Will you ever need to apply this to other numbers besides the single input provided in your example?
- Will all phone numbers contain the same number of characters?
- Will all replacement prefixes be the same?
- Are there other sub-strings that will need to be replaced?
- Do you need to worry about whether or not a given String matches some other String or pattern before doing the replacement?
I could go on, but you get the idea.
Making Some Assumptions
Since we don't have full specifications, let's put some assumptions in place to make this easier. Here are some of the assumptions I'm making in order to provide a solution. The possible solution space will change if these assumptions are invalidated.
- The prefix to be replaced is neither a fixed string nor a fixed length.
- The prefix to be replaced is not guaranteed to be unique within the input string.
- The number of valid digits to be kept may vary in length.
- The length of the valid right-hand portion of the String (the part after the prefix to be replaced) is either a fixed size or its length is known by the calling method.
- You want to exclusively use String methods that don't expose regular expressions, whether or not they are implemented as strings or regexp pattern matches under the hood within Ruby's internals.
If these assumptions remain valid, then that leads us to a number of fixed-string and character-based solutions, of which I will propose just one. Other solutions are possible, so your mileage may vary.
Fixed-String Solution with Replacement Prefix
Here's a solution that is reasonably flexible, and is based solely on slicing the input string by a defined trailing length rather than pattern matching.
# Return a String containing a phone number with
# a new prefix prepended to a suffix of defined
# length.
#
# @param str [String] a phone number with a
# suffix of +sfx_len+ valid digits
# @param sfx_len [Integer] suffix length is the
# negated absolute value of the number of
# characters extracted from the right-most
# side of +str+
# @param prefix [String] new country code that
# will be prepended to the trimmed +str+
# @raise [TypeError] when trying to append to
# +prefix+ when +str[]+ returns nil; for
# example, this will happen if the +sfx_len+
# exceeds the number of characters in +str+
# @return [String] modified phone number with
# prefixed with a new country code
def apply_prefix str, sfx_len=9, prefix="+44"
prefix + str[-(sfx_len.abs)..-1]
end
apply_prefix "045723456789"
#=> "+44723456789"
Other solutions using String#delete_prefix are also possible, but such solutions don't fit our current set of assumptions. Neither does String#sub, even with a fixed-string pattern, unless you can guarantee that the same pattern of characters would never appear later in the phone number and thus could avoid using regular expression atoms for anchoring. The proffered solution doesn't require anchoring per se, but it does require that the caller knows how many characters in str will be considered valid in the event that the default suffix length of 9
is not always correct.

- 81,402
- 15
- 141
- 199
I would likely do something like what @Cary Swoveland already suggested but another option is to use partition
:
def prefixer(str, ch, replace)
"#{replace}#{str.partition(ch)[1, 2].join}"
end
prefixer("045723456789", "7", "+44")
#=> "+44723456789"
prefixer("045123456789", "7", "+44")
#=> "+44789"
prefixer("045123456189", "7", "+44")
#=> "+44"
I'm obviously making a lot of assumptions, particularly as to what should happen if ch
isn't the 4th character in and what should happen if ch
doesn't exist in the string at all.