Short filenames based on weighted curve

Here is a small function that will shorten a filename based on a weighted curve.
I used a simple sine curve given the start and end of the filename the highest weights.

/**
 * This function will return a shorter representation of the path.
 * Each token in the path is given a certain weight based on it's position in the filename.
 * Tokens with lower weight are removed first to achieve the desired length.
 * Tokens at the start and end of the filename have higher weights, the last token has the heighest weight.
 * @param	filename The filename to operate on
 * @param	maxChars The maximum length of the returned filename.
 * The length of the slash character is taken into account.
 * Note: The function will always return a string that is at least 3 chars in length. This would be "..."
 * @param allowPartials Allow tokens be partially visible instead of stripping them completely to fit the desired size
 * @return The shortened filename
 */
public static function shorten( filename:String, maxChars:uint, allowPartials:Boolean = false ):String {
	if( filename.length <= maxChars ) return filename;

	var tokens:Array = filename.split( SLASH );
	var weightedTokens:Array = new Array( tokens.length );

	for( var i:uint = 0; i < weightedTokens.length; ++i ) {
		var weight:Number = Math.abs( Math.sin( i / ( weightedTokens.length - 1 ) * Math.PI - Math.PI * 0.5 ) );
		weightedTokens[ i ] = { token: tokens[ i ], weight: weight, position: i };
	}
	weightedTokens[ weightedTokens.length - 1 ].weight += 1; // Last token has the highest weight possible

	weightedTokens.sortOn( "weight", Array.NUMERIC | Array.DESCENDING );

	var currentLength:uint = 0;
	var lastToken:uint = 0;
	for( lastToken = 0; lastToken < weightedTokens.length; ++lastToken ) {
		var currentTokenLength:uint = String( weightedTokens[ lastToken ].token ).length;

		if( currentLength + currentTokenLength + 3 + ( lastToken * SLASH.length ) >= maxChars ) {
			if( allowPartials ) {
				var diff:int = maxChars - ( currentLength + currentTokenLength + 3 + ( lastToken * SLASH.length ) );
				var finalDiff:int = diff - ( 3 + SLASH.length );
				if( currentTokenLength + finalDiff > 0 ) {
					weightedTokens[ lastToken ].token = String( weightedTokens[ lastToken ].token ).substr( 0, currentTokenLength + finalDiff ) + "...";
					++lastToken;
				}
			}
			break;
		}

		currentLength += currentTokenLength;
	}

	if( currentLength == 0 ) {
		return "...";
	}

	if( lastToken < weightedTokens.length ) {
		weightedTokens.splice( lastToken, weightedTokens.length - lastToken, { token: "...", weight: 0, position: weightedTokens[ lastToken ].position } );
	}
	weightedTokens.sortOn( "position", Array.NUMERIC );

	var shortFilename:String = "";
	for( var tokenIdx:uint = 0; tokenIdx < weightedTokens.length; ++tokenIdx ) {
		if( tokenIdx > 0 ) shortFilename += SLASH;
		shortFilename += String( weightedTokens[ tokenIdx ].token );
	}

	return shortFilename;
}

2 Responses to “Short filenames based on weighted curve”

  1. gencha Says:

    Of course, SLASH has to be defined for this to work. And example would be:
    public static const SLASH:String = “\\”;

  2. Russian Says:

    hi…

    thanks…

Leave a Reply

You must be logged in to post a comment.