Ruby正则表达式 - 用文本中间的空格替换点

时间:2016-10-11 08:46:36

标签: ruby regex

我有一个很长的文字,我想用空格替换点,但只在文本的中间。 例如:

Domain:...................google.com

我需要这个:

Domain:                   google.com

我发现这个正则表达式用一个空格替换点:

str.gsub!(/(?<=:)\.+(?=[^\.])/, ' ')

但这还不够,因为它产生了:

Domain: google.com

我需要保留与点一样多的空间。 你会如何解决它?

3 个答案:

答案 0 :(得分:4)

你快到了,你的正则表达式很好,只需使用String#gsub的块版本来计算替换的匹配长度:

▶ str = 'Domain:...................google.com'
#⇒ "Domain:...................google.com"
▶ str.gsub(/(?<=:)\.+(?=[^\.])/) { |m| ' ' * m.length }
#⇒ "Domain:                   google.com"

答案 1 :(得分:3)

如果您需要在您描述的上下文中执行此操作(使用:分隔的键/值,其中值为域名),您只需使用:

> s='Domain:............www.google.com'
 => "Domain:............www.google.com" 
> s.gsub(/(?<=[:.])\./, ' ')
 => "Domain:            www.google.com"

因为域名不包含:或连续点。

有关更一般的用法,请参阅@mudasobwa答案,或者您也可以这样做:

s.gsub(/(?:\G(?!\A)|\A[^:]*:\K)\./, ' ')

(如果\G锚点与上一次匹配后的位置匹配,则强制下一个结果为连续的。)

答案 2 :(得分:1)

听起来你希望用一个句号之前或之后用空格替换一个句号,我假设在一串句点之前不一定有一个冒号。如果是这样,有两种方法可以做到这一点。

str = "Domain:...................google.com"

使用Enumerable#each_cons代替正则表达式

" #{str} ".each_char.each_cons(3).map { |before,ch,after|
  ch=='.' && (before=='.' || after== '.') ? ' ' : ch }.join
  #=> "Domain:                   google.com"

步骤如下。

s = " #{str} "
  #=> " Domain:...................google.com " 
a = s.each_char
  #=> #<Enumerator: " Domain:...................google.com ":each_char> 
e = a.each_cons(3)
  #=> #<Enumerator: #<Enumerator: " Domain:...................google.com ":
  #     each_char>:each_cons(3)> 

请注意e如何被视为复合枚举器。我们可以通过将它转换为数组来查看此枚举器生成的元素。

e.to_a
  #=> [[" ", "D", "o"], ["D", "o", "m"], ["o", "m", "a"], ["m", "a", "i"],
  #    ["a", "i", "n"], ["i", "n", ":"], ["n", ":", "."], [":", ".", "."],
  #    [".", ".", "."], [".", ".", "."], [".", ".", "."], [".", ".", "."],
  #    [".", ".", "."], [".", ".", "."], [".", ".", "."], [".", ".", "."], 
  #    [".", ".", "."], [".", ".", "."], [".", ".", "."], [".", ".", "."],
  #    [".", ".", "."], [".", ".", "."], [".", ".", "."], [".", ".", "."],
  #    [".", ".", "."], [".", ".", "g"], [".", "g", "o"], ["g", "o", "o"],
  #    ["o", "o", "g"], ["o", "g", "l"], ["g", "l", "e"], ["l", "e", "."],
  #    ["e", ".", "c"], [".", "c", "o"], ["c", "o", "m"], ["o", "m", " "]] 

继续,

b = e.map { |before,ch,after| ch=='.' && (before=='.' || after== '.') ? ' ' : ch }
  #=> ["D", "o", "m", "a", "i", "n", ":", " ", " ", " ", " ", " ", " ", " ",
  #    " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "g", "o",
  #    "o", "g", "l", "e", ".", "c", "o", "m"] 
b.join
  #=> "Domain:                   google.com" 

使用正则表达式

r = /
    (?<=\A|\.) # match the beginning of string or a period in a positive lookbehind
    \.         # match a period
    |          # or
    \.         # match a period
    (?=\.|\z)  # match a period or the end of the string
    /x         # free-spacing regex definition mode 

str.gsub(r,' ')
  #=> "Domain:                   google.com"