特定のキーワードを持つ部分文字列エクストラクタ

Jan 07 2021

チャレンジ

このチャレンジの目標は、入力文字列、開始キーワード、および終了キーワードを受け取る関数を作成することです。出力抽出された結果は、指定された開始キーワードから(ただし除外された)終了キーワードまで(ただし除外された)です。出力部分文字列は、以下の規則に従います。

  • いずれの場合も、出力部分文字列の先頭/末尾のスペースを削除する必要があります。

  • 指定されたstartキーワードが空の文字列である場合、アンカーが入力文字列の先頭にあることを意味します。それ以外の場合、指定されたstartキーワードの最初の出現は開始アンカーです。指定されたstartキーワードが出現しない場合、出力は空の文字列です。

  • 指定されたendキーワードが空の文字列である場合、アンカーが入力文字列の最後にあることを意味します。それ以外の場合、指定されたendキーワードの最初の出現は終了アンカーです。指定されたendキーワードが出現しない場合、出力は空の文字列です。

  • 開始アンカーの位置が終了アンカーの位置より後の場合、または指定された開始キーワードの最初の出現の一部と指定された終了キーワードの最初の出現の一部が重複している場合、出力は空の文字列になります。

指定された文字列から文字列を抽出するのと似ていますが、異なります。指定された開始アンカーと終了アンカーは複数の文字です。

これがC#でのゴルフされていないリファレンス実装です

private static string GetTargetString(string stringInput, string startKeywordInput, string endKeywordInput)
{
    int startIndex;
    if (String.IsNullOrEmpty(startKeywordInput))
    {
        startIndex = 0;
    }
    else 
    {
        if (stringInput.IndexOf(startKeywordInput) >= 0)
        {
            startIndex = stringInput.IndexOf(startKeywordInput) + startKeywordInput.Length;
        }
        else
        {
            return "";
        }
        
    }

    int endIndex;
    if (String.IsNullOrEmpty(endKeywordInput))
    {
        endIndex = stringInput.Length;
    }
    else
    {
        if (stringInput.IndexOf(endKeywordInput) > startIndex)
        {
            endIndex = stringInput.IndexOf(endKeywordInput);
        }
        else
        {
            return "";
        }
    }
    
    
    //    Check startIndex and endIndex
    if (startIndex < 0 || endIndex < 0 || startIndex >= endIndex)
    {
        return "";
    }

    if (endIndex.Equals(0).Equals(true))
    {
        endIndex = stringInput.Length;
    }
    int TargetStringLength = endIndex - startIndex;
    return stringInput.Substring(startIndex, TargetStringLength).Trim();
}

入力と出力の例

入力と出力の例を以下に示します。

入力文字列 開始キーワード 終了キーワード 出力
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 ""(空の文字列) ""(空の文字列) 「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 ""(空の文字列) "。ネット" 「C#はその一部としてMicrosoftによって2000年頃に開発されました」
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 「C#」 ""(空の文字列) 「.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 「C#」 "。ネット" 「その一部としてマイクロソフトによって2000年頃に開発されました」
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 "。ネット" ""(空の文字列) "主導権"
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 ""(空の文字列) 「C#」 ""(空の文字列)
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 "。ネット" 「C#」 ""(空の文字列)
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 「ABC」 「C#」 ""(空の文字列)
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 "。ネット" 「XYZ」 ""(空の文字列)
「C#は、.NETイニシアチブの一環としてMicrosoftによって2000年頃に開発されました」 「ABC」 「XYZ」 ""(空の文字列)

ルール

これはコードゴルフです。バイト数が最も少ない答えが優先されます。

回答

2 Adám Jan 07 2021 at 15:32

APL(Dyalog Extended)、24バイト(SBCS)

の配列の入力を求める完全なプログラム[EndKeyword,StartKeyword,InputString]。0ベースのインデックス付けが必要です。

⌂deb⊃(⌽⊢↓⍨1⍳⍨⊣,⍷)/⌽¨@0⊢⎕

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

 入力のプロンプト

 その上で…

⌽¨@0 オフセット0で発生するすべての要素を反転します

()/ 次の暗黙の関数を使用して、右から減らします。

 左の引数が右の引数で始まるすべての場所をブールリストで示します

⊣, その前に左の引数を追加します

1⍳⍨ 最初の1のオフセットを見つけます

⊢↓⍨ 正しい引数からその多くの主要な要素を削除します

逆(次回は最後からこれを行い、その後、順序を逆にします)

 1次元配列から0次元配列への縮小によって引き起こされたエンクロージャを開示する

⌂debD elete E nding(先頭と末尾)B lanks

5 Arnauld Jan 07 2021 at 11:31

JavaScriptの(ES6)、 80の 75バイト

これには、以下でエスケープされている印刷不可能な文字が含まれています。

(s,a,b)=>s.replace(b||/$/,"").replace(a,"").match(/ *(.*?) *|$/)[1]||""

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

コメント

(s, a, b) =>          // s = input string, a = start keyword, b = end keyword
  s.replace(          // replace in s:
    b || /$/, // look for the end keyword, or the regex /$/ if it's empty
    "\3"              //   and replace it with ETX (end of text)
  )                   //
  .replace(           // replace in the resulting string:
    a,                //   look for the start keyword
    "\2"              //   and replace it with STX (start of text)
  )                   //
  .match(             // attempt to match:
    /\2 *(.*?) *\3|$/ // "\2" STX ) // " *" followed by optional whitespace // "(.*?)" followed by a non-greedy string (the payload) // " *" followed by optional whitespace // "\3" followed by ETX // "|$"    OR match an empty string to make sure that
                      //           match() doesn't return null
  [1] || ""           // return the payload string, or an empty string if undefined
3 Noodle9 Jan 08 2021 at 19:19

Pythonの3、86の 77 75バイト

movaticaのおかげで9バイト節約できました!!! ovsの
おかげで2バイト節約できました!!!

lambda s,a,b:s[s.find(a):(b in s)*s.find(b)if b else None][len(a):].strip()

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

1 tsh Jan 07 2021 at 13:12

JavaScript(Node.js)、74バイト

(s,a,b)=>s.substr(p=(s+a).indexOf(a)+a.length,b?s.indexOf(b)-p:1/0).trim()

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

非常に簡単です...

1 vrintle Jan 07 2021 at 11:57

Ruby、66バイト

->w,s,e,r=Regexp{"#{w[/#{r.quote s}\K.+(?=#{r.quote e})/]}".strip}

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

正規表現を使用しない別の方法、

Ruby、72バイト

->w,s,e{"#{w[((w+s).index(s)+s.size rescue 0)...w.rindex(e)||0]}".strip}

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

1 movatica Jan 08 2021 at 19:47

Pythonの3、100の85バイト

正規表現バージョンは、まだスライスアルゴリズムに勝るものはありません。

from re import*
r=escape
f=lambda s,b,e:(search(r(b)+'(.+)'+r(e),s)or'  ')[1].strip()

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

1 Neil Jan 09 2021 at 19:04

Retina 0.8.2、60バイト

(.*)¶(.+)?¶.*?\1 *(.*?) *(?<!(?=\2).*)(?(2)\2.*|$)|(.|¶)+ $3

オンラインでお試しください!入力を別々の行の開始、終了、文字列として受け取りますが、リンクは、便宜上、コンマ区切りの文字列、終了、開始から変換するヘッダーを使用してスイートをテストするためのものです。説明:

(.*)¶

startキーワードに一致します。

(.+)?¶

オプションで、空でない終了キーワードに一致します。

.*?\1

文字列内のできるだけ早い段階でstartキーワードと、オプションのスペースを見つけます。

 *(.*?) *

結果をできるだけ短くして(文字列内でendキーワードができるだけ早く見つかるように)一致させますが、その周囲のスペースも削除します。

(?<!(?=\2).*)

この時点で、endキーワードがまだ渡されていないことを確認してください。

(?(2)\2.*|$)

endキーワードが空の場合は、文字列の最後でのみ一致します。それ以外の場合は、endキーワードと文字列の残りの部分に一致します。

|(.|¶)+

何にも一致しなかった場合は、すべて削除してください。

$3

望ましい結果を維持します。

1 att Jan 07 2021 at 13:42

Wolfram言語(Mathematica)、93バイト

sStringTrim@StringTake[s,i=1;If[i*=-1;#=="",0,StringPosition[s,#][[1,i]]]-i&/@#]/._@_:>""&

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

1 GalenIvanov Jan 07 2021 at 15:30

赤、90バイト

func[t s e][p:""if""<> s[append s" "]if e =""[e:[end]]parse t[thru s copy p to[opt" "e]]p]

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

1 Davide Jan 10 2021 at 22:26

C(GCC) 、168の 152 143 132 112バイト

@ceilingcatのおかげで巨大な-38

#define r strstr(c
*f(c,s,e)int*c,*s,*e;{return*e&&r,s)>r,e)|!r,s)|!r,e)||*e&&(*r,e)=0)?"":r,s)+strlen(s)+!!*s;}

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

myjobistobehappy Jan 07 2021 at 13:05

JavaScript(ES6)95 92バイト、正規表現なし!

(i,s,e,t=i.indexOf(s),r=i.lastIndexOf(e))=>t!=-1&r!=-1?(i.substring(t+s.length,r)).trim():''

試してみる方法:

ブラウザのJavaScriptコンソールを開き、以下を貼り付けます。

((i,s,e,t=i.indexOf(s),r=i.lastIndexOf(e))=>t!=-1&r!=-1?(i.substring(t+s.length,r)).trim():'')('C# was developed around 2000 by Microsoft as part of its .NET initiative', 'C#', '.NET')
Neil Jan 09 2021 at 22:40

チャコール、41バイト

≔⎇ζ…θ⌕θζθθ≔⎇η⪫Φ⪪θηκηθθ≔⌕AEθ›ι ¹ε¿ε✂θ⌊ε⊕⌈ε

オンラインでお試しください!リンクは、コードの詳細バージョンへのリンクです。キーワードの1つが空の場合でも、入力に十分な改行を含めるように注意してください。説明:

≔⎇ζ…θ⌕θζθθ

endキーワードが空でない場合は、最初に表示されたときに文字列を切り捨てます。(幸いCycleChop、入力が負の場合、文字列は空に切り捨てられます。)

≔⎇η⪫Φ⪪θηκηθθ

startキーワードが空でない場合は、キーワードで文字列を分割し、最初の要素を破棄して、文字列を再度結合します。startキーワードが文字列に表示されない場合、これにより文字列は空になります。

≔⌕AEθ›ι ¹ε

文字列にスペース以外が含まれていないか確認してください。

¿ε✂θ⌊ε⊕⌈ε

その場合は、最初から最後の非スペースまで印刷します。

DominicvanEssen Jan 11 2021 at 06:31

R、111バイト

function(s,a,b,c=?s,`?`=nchar,r=regexpr)trimws(substr(s,`if`((d=r(a,s,f=T))>0,d+?a,c),`if`(?b,r(b,s,f=T)-1,c)))

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

簡単なアプローチ:使って単語の境界を発見regexpr(引数とはf= ixedTテキスト文字列を正規表現として解釈されないことを確実にするためにRUE)は、取得しsubstrそれらの間のINGを、その後trimwハイトのs両端からペース。

関数ncharregexprはそれぞれ2回使用されるため、1文字のエイリアスを定義する方が短くなります。の場合nchar、単項演算子?をエイリアスとして再定義することもできるため、括弧は必要ありません。残念ながら、このトリックはregexpr、追加の引数fixed = Trueをフィードする必要があるため、ここでは不可能です。

pinkfloydx33 Jan 24 2021 at 20:05

C#114バイト

(i,s,e)=>{int p=(i+(s??="")).IndexOf(s)+s.Length,q=$"{e}"==""?i.Length:i.IndexOf(e);return p<q?i[p..q].Trim():"";}