【问题标题】:Remove all special char except apostrophe删除除撇号以外的所有特殊字符
【发布时间】:2017-09-22 17:42:53
【问题描述】:

给定一个句子,我想统计所有重复的单词: 这是来自 Exercism.io 的一个练习 Word count

例如对于输入"olly olly in come free"

plain olly: 2 in: 1 come: 1 free: 1

我有这个测试的例子:

  def test_with_quotations
    phrase = Phrase.new("Joe can't tell between 'large' and large.")
    counts = {"joe"=>1, "can't"=>1, "tell"=>1, "between"=>1, "large"=>2, "and"=>1}
    assert_equal counts, phrase.word_count
  end

这是我的方法

def word_count
    phrase = @phrase.downcase.split(/\W+/)
    counts = phrase.group_by{|word| word}.map {|k,v| [k, v.count]}
    Hash[*counts.flatten]
  end

对于上面的测试,当我在终端中运行它时出现此故障:

  2) Failure:
PhraseTest#test_with_apostrophes [word_count_test.rb:69]:
--- expected
+++ actual
@@ -1 +1 @@
-{"first"=>1, "don't"=>2, "laugh"=>1, "then"=>1, "cry"=>1}
+{"first"=>1, "don"=>2, "t"=>2, "laugh"=>1, "then"=>1, "cry"=>1}

我的问题是删除除'apostrophe 之外的所有字符...

该方法中的正则表达式几乎可以工作... phrase = @phrase.downcase.split(/\W+/) 但它删除了撇号...

我不想在单词周围保留单引号,'Hello' => Hello 但是Don't be cruel => Don't be cruel

【问题讨论】:

  • 试试/[^'a-z]/
  • 或试试这个:/[a-z']+/i
  • 它保留单引号 :( @dagw
  • @sagarpandya82 都不是
  • 似乎有些混乱,您能否澄清一下您的问题。也许给一个更详尽的例子。>>> 好的,你已经完成了,你现在可以为你的第二个例子说明所需的输出吗?

标签: ruby regex


【解决方案1】:

可能是这样的:

string.scan(/\b[\w']+\b/i).each_with_object(Hash.new(0)){|a,(k,v)| k[a]+=1}

正则表达式使用单词边界 (\b)。 扫描输出一个包含找到的单词的数组,并且对于数组中的每个单词,它们被添加到散列中,每个项目的默认值为零,然后递增。

结果是我的解决方案在查找所有项目并忽略大小写时仍会将项目保留在最初找到它们的情况下。 现在这将是 Nelly 的决定,要么按原样接受,要么在原始字符串或添加到散列的数组项上执行小写。

我会把这个决定留给你 :)

【讨论】:

  • 如果string = "'tis Les' play",您的代码将返回{"tis"=>1, "Les"=>1, "play"=>1},而应该保留两个撇号(不是单引号):{"'tis"=>1, "Les'"=>1, "play"=>1}。这与其说是对您的回答的批评,不如说是对区分单引号和撇号的困难的证明。
  • 那是完美的@grail,感谢您的帮助!也感谢所有试图提供帮助的人:)
  • @CarySwoveland - 不确定您使用的是哪种类型的键盘,但我的键盘上的撇号和单引号是相同的。唯一的区别是它们何时被使用以及你如何在语法上谈论它们,即当用于类似的东西时,它被称为撇号,但当像这样使用时,“这里有一些词”它们被称为单引号他们现在引用文本。因此,您的示例毫无意义。我同意的是,通过引用的意图是将单词保持在一起,因此您可能会期望 {"tis Les"=>1, "play"=>1}
  • @grail,是的,我意识到它们是同一个字符,这对我们编码人员来说是不幸的。 "'tis Les' play" 包含一个单词“'tis”,它是一个以撇号开头的缩写,另一个是 "Les'",它是 Les" 的所有格形式,撇号位于末尾,因为该单词以一个"s"。我的观点很简单,要确定这两个词都包含撇号而不是“tis Les”构成一个用单引号括起来的表达式,这对软件来说将是一个挑战。
  • @CarySwoveland - 啊,现在更有意义了:)
【解决方案2】:

给定:

irb(main):015:0> phrase
=> "First: don't laugh. Then: don't cry."

试试:

irb(main):011:0> Hash[phrase.downcase.scan(/[a-z']+/)
                     .group_by{|word| word.downcase}
                     .map{|word, words|[word, words.size]}
                    ]
=> {"first"=>1, "don't"=>2, "laugh"=>1, "then"=>1, "cry"=>1}

随着您的更新,如果您想删除单引号,请先这样做:

irb(main):038:0> p2
=> "Joe can't tell between 'large' and large."
irb(main):039:0> p2.gsub(/(?<!\w)'|'(?!\w)/,'')
=> "Joe can't tell between large and large."

然后用同样的方法。

但是你说——gsub(/(?&lt;!\w)'|'(?!\w)/,'') 将删除'Twas the night before. 中的撇号,我回答说,如果/(?&lt;!\w)'|'(?!\w)/ 不够,你最终需要构建一个解析器来确定撇号和单引号之间的区别。

您也可以使用单词边界:

irb(main):041:0> Hash[p2.downcase.scan(/\b[a-z']+\b/)
                  .group_by{|word| word.downcase}
                  .map{|word, words|[word, words.size]}
                 ]
=> {"joe"=>1, "can't"=>1, "tell"=>1, "between"=>1, "large"=>2, "and"=>1}

但这也不能解决'Tis the night

【讨论】:

  • 保留单引号' '
  • 但是符合要求,TS没有提到他也想去掉引号。 @Nelly
  • @Nelly:你没有在你的例子中这么说。保留撇号但删除单引号是单独使用正则表达式解决的更难的问题。
  • @Nelly - 我很困惑??在您说的问题中:-我的问题是删除除“撇号”以外的所有字符,但是当提出解决方案时,您会说:-它保留单引号....就是这样,您是否想要它们??跨度>
  • 我想保留这里的撇号 Don't worry 并且我想删除像 'Hello everyone' => Hello everyone 这样的单引号 抱歉我不清楚...
【解决方案3】:

另一种方式:

str = "First: don't 'laugh'. Then: 'don't cry'."
reg = /
      [a-z]         #single letter
      [a-z']+       #one or more letters or apostrophe
      [a-z]         #single letter
      '?            #optional single apostrophe

      /ix           #case-insensitive and free-spacing regex

str.scan(reg).group_by(&:itself).transfor‌​m_values(&:count) 
  #=> {"First"=>1, "don't"=>2, "laugh"=>1, "Then"=>1, "cry'"=>1}

【讨论】:

  • 这在某些情况下可能不起作用,但对你来说可能已经足够了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
  • 2014-01-10
  • 1970-01-01
相关资源
最近更新 更多