各文字で始まる最初の単語を見つける


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"

チャレンジ

入力と出力の両方が文字列表現であるか、言語で最も近い代替である必要があります。

許可されたプログラムまたは機能。

単語は次の少なくとも1つであると考えることができます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>元の文字列で単語が1つのスペースで区切られていると想定できますか?</ s>
-Qwertiy

例からそれを理解したので、コメントに<s> </ s>があります。スペースのトリミングはどうですか?
-Qwertiy

回答:


17

網膜、28バイト:

M!i` \ b(\ w)(?<!\ b \ 1。+)\ w *
¶
 
  • M! -各作品に一致し、改行で区切られたすべての単語を印刷します。
  • i -ケースを無視します。
  • \b(\w) -各単語の最初の文字をキャプチャする
  • (?<!\b\1.+)-文字を照合した後、同じ文字で始まる前の単語がなかったかどうかを確認します。\1.+は少なくとも2文字を確保するため、現在の単語をスキップしています。
  • \w*-残りの単語と一致します。
    上記は単語のみに一致します-他のすべての文字は削除されます。
  • ¶\n -改行をスペースに置き換えます。

オンラインでお試しください!


9

網膜、45バイト

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

\ W +
 
^ | $

単一の正規表現を使用して、同じ\w文字で始まる後の単語を削除し(iオプションでは大文字と小文字を区別し\Wません)、実行を単一のスペースに変換し、結果から先頭/末尾のスペースを削除します。

オンラインでお試しください!

編集:@Kobiの回答を参照してください。M!`


くそー、やっと私を打ち負かした!しかし、私は後読みを理解できませんでした。
-GamrCorps

3
別のRetinaの回答を追加しました- それらが十分に異なっていれば大丈夫だと思います(もちろん、基本的な概念は似ています)。
コビ

1
@Kobiそれははるかに優れているので、私はそれを見てうれしいです:) Retinaのラインオプションについて知っておくべきこととそうでないことを私に気づかせてくれます。
Sp3000

これを実行して、数バイトを節約できますか?i` \b((\w)\w*)\b(?<=\b\2\w*\b.+)(最初の前のスペース\b)その後の行は不要ですか?
リーキー修道女

@KennyLau残念ながら、単語は必ずしもスペースで区切られているわけではないので、それが機能するとは思いません。たとえば、a...a -> a
Sp3000

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

u = regexpの使用は本当に賢い方法です。2バイト節約s=>s.match(u=/\w+/g).filter(w=>u[w=parseInt(w[0],36)]?0:u[w]=1).join' '
-edc65

@ edc65ありがとう。実際、36桁の1桁に対して37の出力が可能なのは非常に便利です。
user81655

7

Pyth、23バイト

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

オンラインで試す:デモンストレーションまたはテストスイート

J:z"\w+"1は、正規表現\w+を使用して入力内のすべての単語を検索し、に保存しますJ

.grhk0J小文字の最初の文字で単語をhMグループ化し、各グループの最初のxDJ単語を取得し、入力文字列のインデックスでこれらの単語を並べ替えjd、それらの間にスペースを入れます。



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、スペースに期待されるすべてのものと一致しますが、メタチャーを範囲に入れる方法がわかりません。誰かがヒントを持っているなら、私はemを聞きたいです。


3
なぜa-zA-Z_ありませんか\w?数字が有効です
-edc65

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+çTry here)を使用して、入力文字列から削除する必要があるすべての文字を生成します。を使用Jしてこの文字列を結合し[a-zA-Z0-9_]、žjに保存されているものを削除します(こちらをお試しください)。最初の文字列から2番目の文字列にあるすべての文字を削除します。

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

ここでもテストできますDこれを複製Xし、U-コマンドで保存します。次に、この文字列に含まれるすべての文字を入力から削除します。次に、空白文字を使用して分割しð¡、すべての空の文字列を削除します(を使用""K)。私たちは、今持っているこれを

これは入力のクリーンバージョンであり、これを使用します。を使用して各要素をマッピングしますv。これはy、文字列変数として使用します。すべての禁止文字()を含む文字列を含む¬およびpush を使用して、文字列の最初の文字を取得します。を使用して、この文字列に最初の文字のowercaseバージョン(これもレジスタに対応します)があるかどうかを確認します。この部分で覆われている:禁止文字の文字列()に最初の文字が存在しない場合、この文字を禁止文字のリスト(で行われます)に追加し、スタックの一番上にプッシュします。X!"#$%&'()*+,-./:;<=>?@[\]^`{|}~l©åï>iXX®«Uy

最後に、文字列がフィルタリングされると、スペースでスタックを結合しますðý


1
... 説明?:-)
ルイスメンドー

@LuisMendo思い出させてくれてありがとう!完了:)
アドナン

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

Ungolfedおよび単体テストあり:

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こともh[0]機能します。
バリューインク

1

grepおよびawk、68 56バイト

スクリプト:

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

説明:

  • grep -o 法律用語に一致し、それぞれ独自の行に出力します。

  • awkで各行の最初の文字をsubstr取得し、小文字にし、そのキーでハッシュテーブルエントリをインクリメントします。増分前に値が設定されていなかった場合、行が出力されます。

  • echo ... 行を単語に戻します

私は、以前のないソリューションを作成しようとしたawk使用して、uniqsortgrepbashちょうど下回りました。編集の履歴。

デニスのおかげで、私が見落としていたいくつかの改善に感謝します。


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

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"
]


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.