3

サーバー メッセージを Twitter でクライアントに公開したいと考えています。
残念ながら、Twitter では 140 文字以下の投稿しか許可されていません。これは残念です。

ここで、サーバーからのさまざまなメッセージを連結して最大 140 文字に短縮するアルゴリズムを作成する必要があります。

それはかなりトリッキーです。


コード

static string concatinateStringsWithLength(string[] strings, int length, string separator) {
    // This is the maximum number of chars for the strings
    // We have to subtract the separators
    int maxLengthOfAllStrings = length - ((strings.Length - 1) * separator.Length);

    // Here we save all shortenedStrings
    string[] cutStrings = new string[strings.Length];

    // This is the average length of all the strings
    int averageStringLenght = maxLengthOfAllStrings / strings.Length;

    // Now we check how many strings are longer than the average string
    int longerStrings = 0;
    foreach (string singleString in strings)
    {
        if (singleString.Length > averageStringLenght)
        {
            longerStrings++;
        }
    }

    // If a string is smaller than the average string, we can more characters to the longer strings
    int maxStringLength = averageStringLenght;
    foreach (string singleString in strings)
    {
        if (averageStringLenght > singleString.Length)
        {
            maxStringLength += (int)((averageStringLenght - singleString.Length) * (1.0 / longerStrings));
        }
    }

    // Finally we shorten the strings and save them to the array
    int i = 0;
    foreach (string singleString in strings)
    {
        string shortenedString = singleString;
        if (singleString.Length > maxStringLength)
        {
            shortenedString = singleString.Remove(maxStringLength);
        }

        cutStrings[i] = shortenedString;
        i++;
    }


    return String.Join(separator, cutStrings);
}

これに関する問題

このアルゴリズムは機能しますが、あまり最適化されていません。実際よりも少ない文字を使用します。

これに関する主な問題は、変数が、および後方にlongerStrings相対的であることです。maxStringLength

これは、私が変更しlongerStringsた場合、変更された場合などを意味maxStringLengthします。while ループを作成して、変更がなくなるまでこれを行う必要がありますが、このような単純なケースでは必要ないと思います。

続行する方法の手がかりを教えてもらえますか?

それとも、似たようなものがすでに存在するのでしょうか?

ありがとう!


編集

サーバーから受け取るメッセージは次のようになります。

  • メッセージ
    • 主題
    • 日にち
  • メッセージ
    • 主題
    • 日にち

等々。

私が望むのは、文字列を区切り記号 (この場合はセミコロン) で連結することです。
最大長があるはずです。長い弦は最初に短くする必要があります。

これは主題
です これは体で、少し長いです...
25.02.2013

これは...
これは...
25.02.2013

私はあなたがアイデアを得ると思います;)

4

1 に答える 1

1

あなたのものよりも 5 倍遅くなりますが (この単純な例では)、最大の使用可能なスペースを使用する必要があります (重要な値のチェックはありません):

static string Concatenate(string[] strings, int maxLength, string separator)
{
    var totalLength = strings.Sum(s => s.Length);
    var requiredLength = totalLength - (strings.Length - 1)*separator.Length;

    // Return if there is enough place.
    if (requiredLength <= maxLength)
        return String.Concat(strings.Take(strings.Length - 1).Select(s => s + separator).Concat(new[] {strings.Last()}));

    // The problem...
    var helpers = new ConcatenateInternal[strings.Length];
    for (var i = 0; i < helpers.Length; i++)
        helpers[i] = new ConcatenateInternal(strings[i].Length);

    var avaliableLength = maxLength - (strings.Length - 1)*separator.Length;
    var charsInserted = 0;
    var currentIndex = 0;

    while (charsInserted != avaliableLength)
    {
        for (var i = 0; i < strings.Length; i++)
        {
            if (charsInserted == avaliableLength)
                break;

            if (currentIndex >= strings[i].Length)
            {
                helpers[i].Finished = true;
                continue;
            }

            helpers[i].StringBuilder.Append(strings[i][currentIndex]);
            charsInserted++;
        }
        currentIndex++;
    }

    var unified = new StringBuilder(avaliableLength);
    for (var i = 0; i < strings.Length; i++)
    {
        if (!helpers[i].Finished)
        {
            unified.Append(helpers[i].StringBuilder.ToString(0, helpers[i].StringBuilder.Length - 3));
            unified.Append("...");
        }
        else
        {
            unified.Append(helpers[i].StringBuilder.ToString());
        }

        if (i < strings.Length - 1)
        {
            unified.Append(separator);
        }
    }

    return unified.ToString();
}

そしてConcatenateInternal :

class ConcatenateInternal
{
    public StringBuilder StringBuilder { get; private set; }
    public bool Finished { get; set; }

    public ConcatenateInternal(int capacity)
    {
        StringBuilder = new StringBuilder(capacity);
    }
}
于 2013-02-25T14:12:59.290 に答える