查找每个字母开头的第一个单词


25

给定一个字符串,找到每个字母开头的第一个单词(不区分大小写)。

样品

使用Ferulas flourish in gorgeous gardens.的输入:

"Ferulas flourish in gorgeous gardens."
 ^^^^^^^          ^^ ^^^^^^^^
 |                |  |
 |                |  --> is the first word starting with `g`
 |                --> is the first word starting with `i`
 --> is the first word starting with `f`

然后,此样本的输出应该是匹配的单词,并用一个空格隔开:

"Ferulas in gorgeous"

挑战

输入和输出都必须是字符串表示形式,或者是您语言中最接近的替代形式。

允许的程序或功能。

您可以认为一个单词至少是以下之一:lowercase or uppercase letters, digits, underscore

这是,最短答案以字节为单位。

另一个样本:

input: "Take all first words for each letter... this is a test"
output: "Take all first words each letter is"

input: "Look ^_^ .... There are 3 little dogs :)"
output: "Look _ There are 3 dogs"

input: "...maybe some day 1 plus 2 plus 20 could result in 3"
output: "maybe some day 1 plus 2 could result in 3"

是否允许尾随/起始空格?<s>我可以假设单词在原始字符串中用一个空格分隔吗?</ s>
Qwertiy

我从示例中了解了它,因此注释中有<s> </ s>。修剪空间呢?
Qwertiy

Answers:


17

视网膜,28个字节:

M!i` \ b(\ w)(?<!\ b \ 1。+)\ w *
¶
 
  • M! -匹配每个作品并打印所有用换行符分隔的单词。
  • i -忽略大小写。
  • \b(\w) -捕获每个单词的第一个字母
  • (?<!\b\1.+)-匹配字母后,​​检查是否没有以相同字母开头的前一个单词。\1.+确保至少两个字符,因此我们跳过了当前单词。
  • \w* -匹配其余单词。
    以上仅匹配单词-其他所有字符均被删除。
  • ¶\n -用空格替换换行符。

在线尝试!


9

视网膜,45字节

i` \ b(((\ w)\ w *)\ b(?<= \ b \ 2 \ w * \ b。+)

\ W +
 
^ | $

只需使用单个正则表达式删除以相同\w字符开头的后续单词(此i选项不区分大小写),将游程转换\W为单个空格,然后从结果中删除任何前导/后缀空格。

在线尝试!

编辑:请参阅@Kobi的答案以使用以下较短版本M!`


该死,勉强击败了我!我不知道后面的样子。
GamrCorps '16

3
我添加了另一个Retina答案- 如果它们彼此之间足够不同(我的基本概念是相似的),我认为可以。
科比

1
@Kobi更好,所以我很高兴看到它:)使我意识到我需要了解更多有关Retina的线选项的知识,而不必了解什么。
Sp3000

您可以这样做以节省一些字节吗?i` \b((\w)\w*)\b(?<=\b\2\w*\b.+)(第一个空格\b)以后的行是否不必要?
Leaky Nun

@KennyLau不幸的是,我不认为这是可行的,因为单词不一定要用空格隔开,例如a...a -> a
Sp3000 2016年

9

JavaScript(ES6),73 71字节

s=>s.match(u=/\w+/g).filter(w=>u[n=parseInt(w[0],36)]?0:u[n]=1).join` `

感谢@ edc65,节省了2个字节!

测试

var solution = s=>s.match(u=/\w+/g).filter(w=>u[n=parseInt(w[0],36)]?0:u[n]=1).join` `;
var testCases = [
  "Ferulas flourish in gorgeous gardens.",
  "Take all first words for each letter... this is a test",
  "Look ^_^ .... There are 3 little dogs :)",
  "...maybe some day 1 plus 2 plus 20 could result in 3"
];
document.write("<pre>"+testCases.map(t=>t+"\n"+solution(t)).join("\n\n")+"</pre>");


使用parseInt("_",36) = NaN?亵渎!
Sp3000

1
有趣的事实是:它可以工作@ Sp3000
edc65 '16

使用u = regexp确实很聪明。保存2个字节s=>s.match(u=/\w+/g).filter(w=>u[w=parseInt(w[0],36)]?0:u[w]=1).join' '
edc65 '16

@ edc65谢谢。实际上,对于一个基数为36的数字有37种可能的输出是非常方便的。
user81655 '16

7

Pyth,23个字节

J:z"\w+"1jdxDJhM.grhk0J

在线尝试:演示测试套件

J:z"\w+"1使用正则表达式查找输入中的所有单词\w+并将其存储在中J

.grhk0J用小写的第一个字母对单词进行hM分组,从每个组中选择第一个字母,然后xDJ按输入字符串中的索引对这些单词进行排序,并jd在它们之间放置空格。


4

Perl 6,39个字节

{.words.grep({!%.{.substr(0,1).lc}++})}

1
42个字节,用于固定必须匹配的单词\w+和高尔夫球substr部分
Jo King

3

C,142 132 122字节

@tucuxi减轻了10个字节!

b[200],k;main(c){for(;~c;isalnum(c)|c==95?k&2?:(k|=!b[c|32]++?k&1?putchar(32):0,7:2),k&4?putchar(c):0:(k&=1))c=getchar();}

在最后一个输出字之后打印尾随空格。


1
你可以刮胡子了检查c>47,并c<58通过使用isalnum替代isalpha
南美长吻海豚

3

MATL,23字节

'\w+'XXtck1Z)t!=XRa~)Zc

这借 Jakube的想法,即使用正则表达式来删除不需要的字符并同时进行拆分。

输入是用单引号引起来的字符串。

在线尝试!

说明

'\w+'XX  % find words that match this regexp. Gives a cell array
t        % duplicate
c        % convert into 2D char array, right-padded with spaces
k        % make lowercase
1Z)      % get first column (starting letter of each word)
t!=      % duplicate, transpose, test for equality: all combinations  
XR       % set diagonal and below to 0
a~       % true for columns that contain all zeros       
)        % use as a logical index (filter) of words to keep from the original cell array
Zc       % join those words by spaces

2

Vim 57击键

:s/[^a-zA-Z_ ]//g<cr>A <cr>ylwv$:s/\%V\c<c-v><c-r>"\h* //eg<c-v><cr>@q<esc>0"qDk@q

说明:

:s/[^a-zA-Z_ ]//g                                 #Remove all invalid chars.
A <cr>                                            #Enter insert mode, and enter 
                                                  #a space and a newline at the end
ylwv$:s/\\c%V<c-v><c-r>"\h* //eg<c-v><cr>@q<esc>  #Enter all of this text on the 
                                                  #next line

0                                                 #Go to the beginning of the line
"qD                                               #Delete this line into register
                                                  #"q"
k@q                                               #Run "q" as a macro  

#Macro
ylw                                               #Yank a single letter
   v$                                             #Visual selection to end of line
     :s/                                          #Substitute regex
       \%V\c                                      #Only apply to the selection and 
                                                  #ignore case
            <c-v><c-r>"                           #Enter the yanked letter
                       \h*                        #All "Head of word" chars
                                                  #And a space
                           //                     #Replace with an empty string
                             eg                   #Continue the macro if not found
                                                  #Apply to all matches
                               <c-v><cr>          #Enter a <CR> literal
                                        @q<esc>   #Recursively call the macro

我真的对这个多久感到失望。“无效的”字符(一切,但a-zA-Z_和空间)真把我摔下。我敢肯定有更好的方法可以做到这一点:

:s/[^a-zA-Z_ ]//g

由于\h匹配所有对空间的期望,但是我不知道如何将metachar放在一个范围内。如果有人有提示,我很想听听他们的声音。


3
为什么a-zA-Z_和不\w?数字有效
edc65 '16

2

利亚,165个 155 151 129 102字节

g(s,d=[])=join(filter(i->i!=0,[(c=lcfirst(w)[1])∈d?0:(d=[d;c];w)for w=split(s,r"\W",keep=1<0)])," ")

这是一个接受字符串并返回字符串的函数。

取消高尔夫:

function g(s, d=[])
    # Split the string into an array on unwanted characters, then for
    # each word, if the first letter has been encountered, populate
    # this element of the array with 0, otherwise note the first letter
    # and use the word. This results in an array of words and zeros.
    x = [(c = lcfirst(w)[1])  d ? 0 : (d = [d; c]; w) for w = split(s, r"\W", keep=1<0)]

    # Remove the zeros, keeping only the words. Note that this works
    # even if the word is the string "0" since 0 != "0".
    z = filter(i -> i != 0, x)

    # Join into a string and return
    return join(z, " ")
end

在Sp3000的帮助下节省了53个字节!



2

C#(LINQPAD) - 136个 128字节

var w=Util.ReadLine().Split(' ');string.Join(" ",w.Select(s=>w.First(f=>Regex.IsMatch(""+f[0],"(?i)"+s[0]))).Distinct()).Dump();

2

05AB1E,40个字节

码:

94L32+çJžj-DU-ð¡""Kvy¬Xsl©åï>iX®«Uy}\}ðý

在线尝试!

说明:

我们首先使用94L32+ç试试这里)生成所有应从输入字符串中删除的字符。我们使用J并删除[a-zA-Z0-9_]存储在žj中的字符串(尝试在此处)来加入该字符串。我们从第一个字符串中删除第二个字符串中的所有字符,这将使我们离开:

!"#$%&'()*+,-./:;<=>?@[\]^`{|}~

也可以在这里进行测试。我们将其D更新,然后X使用U-command 存储到。然后,我们从输入中删除此字符串中的所有字符。然后,我们使用分割空格,ð¡并删除所有空字符串(使用""K)。现在我们有了这个

这是输入的纯净版本,我们将使用它。我们使用映射每个元素v。这y用作字符串变量。我们使用¬和push 获取字符串的第一个字符X,其中包含带有所有禁止字符(!"#$%&'()*+,-./:;<=>?@[\]^`{|}~)的字符串。我们使用以下命令检查该l字符串中是否有第一个字符的大写版本(也将©与寄存器相对应)å。本部分介绍:ï>i,如果禁止字符(X)的字符串中不存在第一个字母,则将该字母附加到禁止字符列表中(用结束X®«U),然后按y堆栈顶部。

最后,当字符串被过滤时,我们使用空格将堆栈连接起来ðý


1
...解释?:-)
Luis Mendo

@LuisMendo感谢您提醒我!完成:)
阿德南(Adnan)2016年

2

的PHP

受到大多数答案中使用正则表达式的启发,我最初尝试完全不使用正则表达式只是为了展示一个简洁的变化,但是没有干净的字符串作为输入的症结点毁了这个想法。伤心。

带有函数包装,89个字节

function f($s){foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;}

不带函数包装器(需要预先声明$ s),73个字节

foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;

说明:

foreach(preg_split('/\W/',$s)as$w)$c[lcfirst($w)[0]]++?:$v.=" $w";echo$v;
        preg_split('/\w/',$s)                                             Break input on all non-word characters
foreach(                     as$w)                                        Loop through each 'word'
                                     lcfirst($w)[0]                       Take the first letter of the lowercase version of the word
                                  $c[              ]++?:                  Increment an array element with a key of that letter after checking if it's false-y (0)
                                                        $v.=" $w";        Add the word if the letter wasn't found (if the previous condition evaluated to false)
                                                                  echo$v; Print the new string to screen.

我唯一的遗憾是我找不到更快的检查/转换字母大小写的方法。


2

Python,103个字节

import re
lambda s,d=[]:[w for w in re.findall("\w+",s)if(d.append(w.lower()[0])or d[-1])not in d[:-1]]

1

Lua,172字节

最终我想要的时间更长了...

t={}(...):gsub("[%w_]+",function(w)b=nil for i=1,#t
do b=t[i]:sub(1,1):lower()==w:sub(1,1):lower()and 1 or b
end t[#t+1]=not b and w or nil end)print(table.concat(t," "))

不打高尔夫球

t={}                           -- initialise the accepted words list
(...):gsub("[%w_]+",function(w)-- iterate over each group of alphanumericals and underscores
  b=nil                        -- initialise b (boolean->do we have this letter or not)
  for i=1,#t                   -- iterate over t
  do
    b=t[i]:sub(1,1):lower()    -- compare the first char of t's i word
       ==w:sub(1,1):lower()    -- and the first char of the current word
           and 1               -- if they are equals, set b to 1
           or b                -- else, don't change it
  end
  t[#t+1]=not b and w or nil   -- insert w into t if b isn't set
end)

print(table.concat(t," "))     -- print the content of t separated by spaces

1

严重的是43个字节

6╙¬▀'_+,;)-@s`;0@Eùk`M┬i;╗;lrZ`i@╜í=`M@░' j

在线尝试!

缺少正则表达式功能使此过程比需要的困难得多。

说明:

6╙¬▀'_+,;)-@s`;0@Eùk`M┬i;╗;lrZ`i@╜í=`M@░' j
6╙¬▀                                         push digits in base 62 (uppercase and lowercase letters and numbers)
    '_+                                      prepend underscore
       ,;)                                   push two copies of input, move one to bottom of stack
          -                                  get all characters in input that are not letters, numbers, or underscores
           @s                                split input on all occurrences of non-word characters
             `;0@Eùk`M                       for each word: push the first letter (lowercased)
                      ┬i                     transpose and flatten (TOS is list of first letters, then list of words)
                        ;╗                   push a copy of the first letters list to register 0
                          ;lrZ               zip the list of first letters with their positions in the list
                              `i@╜í=`M       for each first letter: push 1 if that is the first time the letter has been encountered (first index of the letter matches its own index) else 0
                                      @░     filter words (take words where corresponding element in the previous list is truthy)
                                        ' j  join on spaces

1

Ruby 76字节

s;f={};s.scan(/(([\w])[\w]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.*' '

或使用方法定义88个字节

def m s;f={};(s.scan(/((\w)\w*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=1; h)}-[p]).*' ';end

取消高尔夫并进行单元测试:

def m_long(s)
  #found  - Hash with already found initials
  f={}
  #h=hit, i=initial, j=i[0].downcase
  s.scan(/(([\w\d])[\w\d]*)/).map{|h,i| 
    f[j=i.upcase] ? nil : (f[j] = true; h)
  }.compact.join(' ')
end
#true == !p
#~ def m(s)
  #~ f={};s.scan(/(([\w\d])[\w\d]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.join' '
#~ end
def m s;f={};s.scan(/(([\w\d])[\w\d]*)/).map{|h,i|f[j=i.upcase]?nil:(f[j]=!p; h)}.compact.join' ';end

#~ s = "Ferulas flourish in gorgeous gardens."
#~ p s.split

require 'minitest/autorun'
class FirstLetterTest < Minitest::Test
  def test_1
    assert_equal("Ferulas in gorgeous",m("Ferulas flourish in gorgeous gardens."))
    assert_equal("Ferulas in gorgeous",m_long("Ferulas flourish in gorgeous gardens."))
  end
  def test_2
    assert_equal("Take all first words each letter is",m("Take all first words for each letter... this is a test"))
    assert_equal("Take all first words each letter is",m_long("Take all first words for each letter... this is a test"))
  end
  def test_3
    assert_equal("Look _ There are 3 dogs",m("Look ^_^ .... There are 3 little dogs :)"))
    assert_equal("Look _ There are 3 dogs",m_long("Look ^_^ .... There are 3 little dogs :)"))
  end
  def test_4
    assert_equal("maybe some day 1 plus 2 could result in 3",m("...maybe some day 1 plus 2 plus 20 could result in 3"))
    assert_equal("maybe some day 1 plus 2 could result in 3",m_long("...maybe some day 1 plus 2 plus 20 could result in 3"))
  end
end

在正则表达式中,\w包含数字字符,因此[\w\d]可以替换为\w。同样,如果nil值在调用时位于数组中join' '(或者更好,这*' '是一种速记,您可以用来节省更多字节),则它们将消失,因此compact无需调用。
价值墨水

@KevinLau谢谢。这\w\d让我很尴尬。但是,如果我删除,则会compact得到额外的空格(请参阅参考资料['x',nil,'x']*'y' == 'xyyx')。还是我错过了什么?
knut

糟糕,您是对的。在这种情况下,(list-[p])将字节保存为list.compact。也,/\w/等效于/[\w]/。最后,你可以取代你nilp和你!p1(因为你只哈希它需要truthy值)
价值墨水

谢谢,我加了你的话,更换nilp不工作。如果在代码中使用它,则会出现语法错误。我必须封装像(p)-但然后我又有3个字符。
knut

翻转三进制,然后保存一个字节:!f[j=i.upcase]?(f[j]=1;h):p。也只是想到了这一点,但是由于字符串索引,也使用s.scan(/\w+/)和删除了i对work的支持h[0]
Value Ink

1

grep and awk,68岁 56字节

剧本:

echo `grep -o '\w*'|awk '!x[tolower(substr($0,1,1))]++'`

说明:

  • grep -o 匹配合法字词,并在每行上分别打印。

  • awk用接受每行的第一个字母substr,使其变为小写,然后使用该键递增哈希表条目。如果在增加之前未设置该值,则会打印该行。

  • echo ... 把线条变成文字

我曾试图创造一个没有解决awk,使用uniqsortgrepbash,但下跌只是短。编辑中的历史记录。

感谢Dennis,我错过了一些改进。


0

Python 3.5,138个字节:

import re;lambda o,t=[]:''.join([y[0]for y in[(u+' ',t.append(u[0].lower()))for u in re.sub('\W+',' ',o).split()if u[0].lower()not in t]])

基本上,正在发生的事情是..

  1. 该程序使用简单的正则表达式用空格替换给定字符串中除小写或大写字母,数字或下划线以外的所有字符,然后在这些空格处拆分字符串。
  2. 然后,使用列表理解,创建一个遍历拆分字符串中所有单词的列表,并将每个单词的首字母添加到列表“ t”中。
  3. 在此过程中,如果当前单词的第一个字母尚未在列表“ t”中,则该单词和尾随空格将添加到正在创建的当前列表中。否则,列表继续将每个单词的前几个字母附加到列表“ t”。
  4. 最后,当拆分中的所有单词都经过迭代后,新列表中的单词将合并为一个字符串并返回。

0

PHP 120字节

function a($s){foreach(preg_split('/\W/',$s)as$w)if(!$o[ucfirst($w[0])]){$o[ucfirst($w[0])]=$w;}return implode(" ",$o);}

这会产生一堆警告,但这很好。


function必要吗?
AL 2016年

0

Javascript ES6, 108 107个字符

107个字符,结果字符串被修剪

r=s=>s.split``.reverse().join``
f=s=>r(r(s).replace(/\b\w*(\w)\b(?=.*\1\b)/gi,'')).replace(/\W+/g,' ').trim()

测试:

["Take all first words for each letter... this is a test",
"Look ^_^ .... There are 3 little dogs :)",
"...maybe some day 1 plus 2 plus 20 could result in 3"
].map(f) + '' == [
"Take all first words each letter is",
"Look _ There are 3 dogs",
"maybe some day 1 plus 2 could result in 3"
]


0

Tcl,150字节

proc F {s D\ {}} {lmap w [split $s] {regsub -all \[^\\w] $w "" f
if {![dict e $D [set k [string tol [string in $f 0]]]]} {dict se D $k $f}}
dict v $D}

在线尝试!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.