简体   繁体   中英

How to find last occurrence of a substring in a given string?

I have a string, which describe some word, I must change ending of it to "sd", if ending == "jk". For an example, I have word: "lazer jk ", I need to get from it "lazer sd ".

I tried to use method.gsub,. but it doesn't work correctly if we have more than one occurrence of substring "jk" in a word.

String#rindex returns the index of the last occurrence of the given substring

String#[]= can take two integers arguments, first is index where start to replace and second - length of replaced string

You can use them this way:

replaced = "foo"
replacing = "booo"

string = "foo bar foo baz"
string[string.rindex(replaced), replaced.size] = replacing

string
# => "foo bar booo baz"
"jughjkjkjk\njk".sub(/jk$\z/, 'sd')
 => "jughjkjkjk\nsd"

without $ is probably sufficient.

It sounds like you're looking to replace a specific suffix only. If so, I would probably suggest using sub along with an anchored regex (to check for the desired characters only at the end of the string):

string_1 = "lazerjk"
string_2 = "lazerjk\njk"
string_3 = "lazerjkr"

string_1.sub(/jk\z/, "sd")  
#=>  "lazersd"

string_2.sub(/jk\z/, "sd")  
#=>  "lazerjk\nsd"

string_3.sub(/jk\z/, "sd")
#=>  "lazerjkr"

Or, you could do without a regex at all by using the reverse! method along with a simple conditional statement to sub! only when the suffix is present:

string = "lazerjk"
old_suffix = "jk"
new_suffix = "sd"
string.reverse!.sub!(old_suffix.reverse, new_suffix.reverse).reverse! if string.end_with? (old_suffix)
string 
#=>  "lazersd"

OR, you could even use a completely different approach. Here's an example using chomp to remove the unwanted suffix and then ljust to pad the desired suffix to the modified string.

string = "lazerjk"
string.chomp("jk").ljust(string.length, "sd")
#=>  "lazersd"

Note that the new suffix only gets added if the length of the string was modified with the initial chomp. Otherwise, the string remains unchanged.

If the goal is to substitute the LAST OCCURRENCE (as opposed to suffix only), then this could be accomplished by using sub along with reverse :

string = "jklazerjkm"
old_substring = "jk"
new_substring = "sd"
string.reverse.sub(old_substring.reverse, new_substring.reverse).reverse
#=>  "jklazersdm"

Replacing "jk" at the end of a string with something else is straightforward and can be addressed without concern for other instances of "jk" that may be in the string, so I assume that is not what is being asked. Rather, I assume the problem is to replace the last instance of "jk" in a string with "sd" .

Here are two solutions that make use of String#sub with a regular expression.

Use a negative lookahead

The idea here is to match "jk" provided it is not followed later in the string by another instance of "jk" .

"lajkz\nejkrjklm".sub(/jk(?!.*jk)/m, "sd")
  #=> "lajkz\nejkrsdlm"

Capture the part of the string that precedes the last "jk"

The match, if there is one, consists of the front of the string followed by the last "jk" , which is replaced by the captured string followed by "sd" .

"lajkz\nejkrjklm".sub(/\A(.*)jk/m) { $1 + "sd" }
  #=> "lajkz\nejkrsdlm"

The two regular expressions can be written in free-spacing mode to make them self-documenting. The first is the following.

/
jk    # match literal
(?!   # begin a negative lookahead
  .*  # match zero or more characters other than line terminators
  jk  # match literal
)     # end negative lookahead
/mx   # invoke multiline and free-spacing regex definition modes.

Multiline mode causes . to match any character, including a line terminator.

The second regular expression can be written as follows.

\A    # match the beginning of the string
(.*)  # match zero or more characters other than line terminators
      # and save the match to capture group 1
jk    # match literal
/mx   # invoke multiline and free-spacing regex definition modes.

Note that in both expressions .* is greedy , meaning that it will match as many characters as possible, including "jk" so long as other requirements of the expression are met, here that the last instance of "jk" in the string is matched.

Here is a different solution:

str = "jughjkjkjk\njk"
pattern = "jk"
replace_with = "sd"
str = str.reverse.sub(pattern.reverse, replace_with.reverse).reverse

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM