繰り返し始まるテキスト行のリンク

繰り返し始まるテキスト行のリンク

次の形式の行を含む長いテキストファイル(stardict-editorのタブファイル)があります。

word1  some text
word1  some other text
word2  more text
word3  even more

そしてそれを次に変換したいです。

word1  some text<br>some other text
word2  more text
word3  even more

これは、同じ単語(ファイルがソートされている)で始まる後続の行を単一の行(ここではdelimitedと定義されている<br>)にマージする必要があることを意味します。同じ開始行が複数回表示されることもあります。単語と定義を区別する文字はタブ文字であり、各行で一意です。word1、、word2word3もちろん、私が事前に知らない任意のコンテンツ(タブと改行を除く)のプレースホルダーです。

これを行うには、より長いPerlコードを考えることができますが、Perlまたはコマンドラインに簡単な解決策があるかどうかを知りたいです。どんなアイデアがありますか?

答え1

perl -p0E 'while(s/^((.+?)\t.*)\n\2\t/$1<br>/gm){}' 

(6年後の私のラップトップでは、150万行の23MB辞書を処理するのに2秒かかります。)

答え2

これは標準的な手順です。awk

awk '
{
  k=$2
  for (i=3;i<=NF;i++)
    k=k " " $i
  if (! a[$1])
    a[$1]=k
  else
    a[$1]=a[$1] "<br>" k
}
END{
  for (i in a)
    print i "\t" a[i]
}' long.text.file

ファイルが行の最初の単語にソートされると、スクリプトがより簡単になる可能性があります。

awk '
{
  if($1==k)
    printf("%s","<br>")
  else {
    if(NR!=1)
      print ""
    printf("%s\t",$1)
  }
  for(i=2;i<NF;i++)
    printf("%s ",$i)
  printf("%s",$NF)
  k=$1
}
END{
print ""
}' long.text.file

そうでなければbash

unset n
while read -r word definition
do
    if [ "$last" = "$word" ]
    then
        printf "<br>%s" "$definition"
    else 
        if [ "$n" ]
        then
            echo
        else
            n=1
        fi
        printf "%s\t%s" "$word" "$definition"
        last="$word"
     fi
done < long.text.file
echo

答え3

これは実際には標準ですawk。作業データを変更しないきれいな解決策は次のとおりです。

awk 'BEGIN { FS="\t" }
     $1!=key { if (key!="") print out ; key=$1 ; out=$0 ; next }
     { out=out"<br>"$2 }
     END { print out }'

答え4

Pythonでは:

import sys

def join(file_name, join_text):
    prefix = None
    current_line = ''
    for line in open(file_name):
        if line and line[-1] == '\n':
            line = line[:-1]
        try:
            first_word, rest = line.split('\t', 1)
        except:
            first_word = None  # empty line or one without tab
            rest = line
        if first_word == prefix:
            current_line += join_text + rest
        else:
            if current_line:
                print current_line
            current_line = line
            prefix = first_word

    if current_line:  # do the last line(s)
        print current_line


join(sys.argv[2], sys.argv[1])

<br>これには、プログラムの最初の引数として区切り文字()が必要になり、2番目の引数としてファイル名が必要です。

関連情報