Temukan kata pertama yang dimulai dengan setiap huruf

25

Diberikan string, cari kata pertama yang dimulai dengan setiap huruf (tidak sensitif huruf).

Mencicipi

Menggunakan Ferulas flourish in gorgeous gardens.sebagai input:

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

Kemudian, output untuk sampel ini harus berupa kata-kata yang cocok yang digabungkan oleh satu spasi tunggal:

"Ferulas in gorgeous"

Tantangan

Baik input maupun output harus berupa representasi string, atau alternatif terdekat dalam bahasa Anda.

Program atau fungsi diizinkan.

Anda dapat mempertimbangkan sebuah kata yang setidaknya salah satu dari: lowercase or uppercase letters, digits, underscore.

Ini adalah , jawaban terpendek dalam byte yang menang.

Sampel lain:

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"
dihapus
sumber
Apakah ruang trailing / starting diperbolehkan? <s> Dapatkah saya menganggap kata-kata dipisahkan oleh satu spasi dalam string asli? </s>
Qwertiy
Saya mengerti dari contoh, jadi ada <s> </s> di komentar. Bagaimana dengan memangkas ruang?
Qwertiy

Jawaban:

17

Retina , 28 byte:

M! I` \ b (\ w) (? <! \ B \ 1. +) \ W *
¶
 
  • M! - Cocokkan masing-masing pekerjaan dan cetak semua kata yang dipisahkan oleh baris baru.
  • i - Abaikan case.
  • \b(\w) - Tangkap huruf pertama dari setiap kata
  • (?<!\b\1.+)- Setelah mencocokkan surat, periksa apakah tidak ada kata sebelumnya yang dimulai dengan huruf yang sama. \1.+memastikan setidaknya dua karakter, jadi kami melewatkan kata saat ini.
  • \w*- cocok dengan sisa kata.
    Kata-kata di atas hanya cocok - semua karakter lain dihapus.
  • ¶\n - Ganti baris baru dengan spasi.

Cobalah online!

Kobi
sumber
9

Retina , 45 byte

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

\ W +
 
^ | $

Cukup gunakan regex tunggal untuk menghapus kata-kata selanjutnya yang dimulai dengan \wkarakter yang sama (case-sensitive with the ioption), mengonversi lari dari \Wke satu ruang, lalu menghapus ruang utama / belakang dari hasilnya.

Cobalah online!

Sunting: Lihat jawaban @ Kobi untuk versi yang lebih pendek menggunakanM!`

Sp3000
sumber
Sialan, nyaris tidak mengalahkan saya untuk itu! Tapi aku tidak tahu apa yang ada di belakang.
GamrCorps
3
Saya telah menambahkan jawaban Retina lain - saya pikir tidak apa-apa jika mereka cukup berbeda (konsep dasarnya serupa, tentu saja).
Kobi
1
@ Kobi Ini jauh lebih baik, jadi saya senang melihatnya :) Membuat saya sadar betapa lebih banyak yang perlu saya pelajari tentang opsi garis Retina dan apa yang tidak.
Sp3000
Bisakah Anda melakukan ini untuk menghemat beberapa byte? i` \b((\w)\w*)\b(?<=\b\2\w*\b.+)(spasi sebelum yang pertama \b) Apakah garis sesudahnya tidak perlu?
Leaky Nun
@ KennyLau Sayangnya, saya tidak berpikir itu berhasil karena kata-kata tidak harus dipisahkan oleh spasi, misalnyaa...a -> a
Sp3000
9

JavaScript (ES6), 73 71 byte

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

Disimpan 2 byte berkat @ edc65!

Uji

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>");

pengguna81655
sumber
Menggunakan parseInt("_",36) = NaN? Penghujatan!
Sp3000
1
Fakta yang menyenangkan adalah: berfungsi @ Sp3000
edc65
Menggunakan u = regexp benar-benar pintar. Simpan 2 bytes=>s.match(u=/\w+/g).filter(w=>u[w=parseInt(w[0],36)]?0:u[w]=1).join' '
edc65
@ edc65 Terima kasih. Sebenarnya cukup nyaman bahwa ada 37 kemungkinan output untuk satu basis-36 digit.
user81655
7

Pyth, 23 byte

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

Cobalah online: Demonstrasi atau Test Suite

J:z"\w+"1menemukan semua kata dalam input menggunakan regex \w+dan menyimpannya dalam J.

.grhk0Jmengelompokkan kata-kata dengan huruf kecil pertama mereka, hMmengambil yang pertama dari setiap kelompok, xDJmengurutkan kata-kata ini dengan indeks mereka dalam string input, dan jdmenempatkan spasi di antara mereka.

Jakube
sumber
4

Perl 6, 39 byte

{.words.grep({!%.{.substr(0,1).lc}++})}
Yang Mulia
sumber
1
42 byte yang memperbaiki kata-kata yang harus cocok \w+dan bermain golf substrbagian
Jo King
3

C, 142 132 122 byte

10 byte lebih ringan berkat @tucuxi!

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();}

Mencetak spasi tambahan setelah kata keluaran terakhir.

mIllIbyte
sumber
1
Anda dapat mencukur cek untuk c>47dan c<58dengan menggunakan isalnumalih-alihisalpha
tucuxi
3

MATL , 23 byte

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

Ini meminjam ide Jakube untuk menggunakan regexp untuk menghapus karakter yang tidak diinginkan dan membelah pada saat yang sama.

Input adalah string yang diliputi oleh tanda kutip tunggal

Cobalah online!

Penjelasan

'\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
Luis Mendo
sumber
2

Vim 57 penekanan tombol

: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

Penjelasan:

: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

Saya benar-benar kecewa dengan berapa lama ini. The "tidak valid" chars (segala sesuatu tetapi a-z, A-Z, _dan ruang) benar-benar melemparkan saya off. Saya yakin ada cara yang lebih baik untuk melakukan ini:

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

Karena \hcocok dengan semua yang diharapkan untuk ruang, tapi saya tidak tahu bagaimana menempatkan metachar dalam kisaran. Jika ada yang punya tips, saya ingin mendengarnya.

DJMcMayhem
sumber
3
mengapa a-zA-Z_dan tidak \w? digit valid
edc65
2

Julia, 165 155 151 129 102 byte

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

Ini adalah fungsi yang menerima string dan mengembalikan string.

Tidak Disatukan:

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

Disimpan 53 byte dengan bantuan dari Sp3000!

Alex A.
sumber
2

Jelly, 32 31 byte

ØB;”_
e€¢¬œṗf€¢¹ÐfµZḢŒlQi@€$ịj⁶

Cobalah online!

Dennis
sumber
2

C # (LINQPAD) - 136 128 byte

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

05AB1E , 40 byte

Kode:

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

Cobalah online!

Penjelasan:

Kami pertama-tama menghasilkan semua karakter yang harus dihapus dari string input menggunakan 94L32+ç( Coba di sini ). Kami bergabung dengan string ini menggunakan Jdan menghapus [a-zA-Z0-9_]yang disimpan di žj ( Coba di sini ). Kami menghapus semua karakter yang ada di string kedua dari string pertama, yang akan meninggalkan kita:

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

Itu juga bisa diuji di sini . Kami Dmenggandakan ini dan menyimpannya Xdengan- Uperintah. Kami kemudian menghapus semua karakter yang ada di string ini dari input. Kami kemudian membagi pada spasi putih menggunakan ð¡dan menghapus semua string kosong (menggunakan ""K). Kami sekarang memiliki ini .

Ini adalah bersih versi masukan, yang kami akan bekerja dengan. Kami memetakan setiap elemen menggunakan v. Ini digunakan ysebagai variabel string. Kami mengambil karakter pertama dari string menggunakan ¬dan mendorong X, yang berisi string dengan semua karakter terlarang ( !"#$%&'()*+,-./:;<=>?@[\]^`{|}~). Kami memeriksa apakah lversi owercase dari karakter pertama, (yang juga akan ©disalin ke register), menggunakan string ini å. Ditutupi oleh bagian ini:, ï>ijika huruf pertama tidak ada dalam string karakter terlarang ( X), kami menambahkan surat ini ke daftar karakter terlarang (selesai dengan X®«U) dan kami mendorong ydi atas tumpukan.

Akhirnya, ketika string difilter, kita bergabung dengan stack dengan spasi ðý.

Adnan
sumber
1
... penjelasan? :-)
Luis Mendo
@LuisMendo Terima kasih telah mengingatkan saya! Selesai :)
Adnan
2

PHP

Terinspirasi oleh penggunaan regex di sebagian besar jawaban, saya awalnya mencoba melakukan ini tanpa menggunakan regex sama sekali hanya untuk memamerkan variasi yang rapi, tetapi titik mencuatnya tidak memiliki string bersih sebagai input merusak ide itu. Sedih.

Dengan fungsi wrapper, 89 byte

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

Tanpa fungsi wrapper (membutuhkan $ s yang telah dideklarasikan), 73 byte

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

Penjelasan:

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.

Satu-satunya penyesalan saya adalah saya tidak dapat menemukan cara yang lebih cepat untuk memeriksa / mengubah huruf.

Xanderhall
sumber
2

Python, 103 byte

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]]
orlp
sumber
1

Lua, 172 Bytes

Itu berakhir jauh lebih lama daripada yang saya inginkan ...

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," "))

Tidak disatukan

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
Katenkyo
sumber
1

Serius, 43 byte

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

Cobalah online!

Kurangnya kemampuan regex membuat ini jauh lebih sulit daripada yang seharusnya.

Penjelasan:

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
Mego
sumber
1

Ruby 76 Bytes

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

Atau dengan metode definisi 88 byte

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

Tidak disatukan dan dengan unit test:

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
knut
sumber
Di Regex, \wsertakan karakter angka, jadi [\w\d]bisa diganti dengan \w. Juga, jika nilnilai-nilai berada dalam array ketika Anda menelepon join' '(atau lebih baik lagi, *' 'adalah singkatan yang dapat Anda gunakan untuk menyimpan lebih banyak byte), mereka menghilang, sehingga panggilan ke compacttidak perlu.
Value Ink
@KevinLau Terima kasih. Ini \w\dmemalukan bagi saya. Tetapi jika saya menghapus compactsaya mendapatkan ruang tambahan, (lihat ['x',nil,'x']*'y' == 'xyyx'). Atau apakah saya melewatkan sesuatu?
knut
Aduh, kau benar. Dalam hal ini, (list-[p])simpan byte lebih dari list.compact. Juga, /\w/setara dengan /[\w]/. Akhirnya, Anda dapat mengganti nildengan pdan !pdengan 1(karena hash Anda hanya membutuhkan nilai yang benar di dalamnya)
Value Ink
Terima kasih, saya menambahkan komentar Anda, Penggantian nildengan ptidak berfungsi. Jika saya menggunakannya di dalam kode saya, saya mendapatkan kesalahan sintaksis. Saya harus merangkum suka (p)- tapi kemudian saya punya lagi 3 karakter.
Knut
Membalik terner dan kemudian bekerja untuk menyimpan byte: !f[j=i.upcase]?(f[j]=1;h):p. Juga hanya memikirkan ini, tetapi karena pengindeksan string, menggunakan s.scan(/\w+/)dan menghapus imendukung h[0]karya juga.
Value Ink
1

grep dan awk, 68 56 byte

Naskah:

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

Penjelasan:

  • grep -o cocok dengan kata-kata hukum, mencetak masing-masing pada barisnya sendiri.

  • awkmengambil huruf pertama dari setiap baris dengan substr, membuatnya menjadi huruf kecil, dan kemudian menambahkan entri hashtable dengan kunci itu. Jika nilainya tidak disetel sebelum kenaikan, garis dicetak.

  • echo ... mengubah garis kembali menjadi kata-kata

Saya sebelumnya mencoba untuk membuat solusi tanpa awk, menggunakan uniq, sort, grepdan bashtapi jatuh hanya singkat. Riwayat dalam suntingan.

Terima kasih kepada Dennis untuk beberapa perbaikan yang saya lewatkan.

joeytwiddle
sumber
0

Python 3.5, 138 byte:

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

Pada dasarnya, apa yang terjadi adalah ..

  1. Dengan menggunakan ekspresi reguler yang sederhana, program ini mengganti semua karakter, kecuali huruf kecil atau huruf besar, angka, atau garis bawah pada string yang diberikan dengan spasi, dan kemudian memisahkan string pada spasi tersebut.
  2. Kemudian, menggunakan pemahaman daftar, buat daftar yang beriterasi melalui semua kata dalam string yang dipisah, dan tambahkan huruf pertama dari setiap kata ke daftar "t".
  3. Dalam prosesnya, jika huruf pertama kata saat ini TIDAK sudah ada dalam daftar "t", maka kata itu dan spasi tambahan ditambahkan ke daftar saat ini sedang dibuat. Kalau tidak, daftar ini terus menambahkan huruf pertama dari setiap kata ke daftar "t".
  4. Akhirnya, ketika semua kata dalam perpecahan telah diulangi, kata-kata dalam daftar baru digabungkan menjadi string dan dikembalikan.
R. Kap
sumber
0

PHP 120bytes

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

Ini menghasilkan banyak peringatan tapi tidak apa-apa.

pengguna52869
sumber
Apakah itu functionperlu?
AL
0

Javascript ES6, 108 107 karakter

107 karakter, string hasil dipangkas

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

Uji:

["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"
]
Qwertiy
sumber
f= tidak masuk hitungan .
Qwertiy
0

Tcl , 150 byte

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}

Cobalah online!

sergiol
sumber