Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 11-14 of 14 total

Path parser //Pascal class

An unit to get the special folders' path under windows and it also parses paths shortcuts in the form "$(shortcut)/folder/file.ext".

unit PathParser;

interface

uses
  Classes, SysUtils, TypInfo, SysUtils2, ShlObj, ShellApi, Registry, Windows;

type
  TSpecialFolder = ( sfDesktop, sfAppData, sfTemplates, sfPrograms,
    sfPersonal, sfFavorites, sfStartup, sfRecent, sfSendTo, sfStartMenu,
    sfFonts, sfHistory, sfCookies, sfInternetCache, sfCommonFavorites,
    sfCommonDesktop, sfCommonStartup, sfCommonPrograms, sfCommonStartMenu,
    sfProgramFiles, sfTemporary, sfWindows, sfSystem );

  TSpecialFolderSet = set of TSpecialFolder;

  TPathParser = class( TStringList )
  public
    constructor Create( const UseDefaultMap: Boolean = True );
    class function GetSpecialFolder( const Name: TSpecialFolder ): string;
    function Parse( Path: string ): string;
  end;


implementation

{ TPathParser }

uses Dialogs;

constructor TPathParser.Create(const UseDefaultMap: Boolean);
var
  I: TSpecialFolder;
begin
  CaseSensitive := False;
  if UseDefaultMap then begin
    for I := Low( TSpecialFolder ) to High( TSpecialFolder ) do
      Add( RemoveSlash( LowerCase( Copy( GetEnumName( TypeInfo( TSpecialFolder ),
        Ord( I ) ), 3, MAX_PATH ) ) + '=' + GetSpecialFolder( I ) ) );
    Add( RemoveSlash( Format( 'windowsvolume=%s', [ GetSpecialFolder( sfWindows )[1] ] ) ) );
  end;
end;

class function TPathParser.GetSpecialFolder(
  const Name: TSpecialFolder): string;
const
  FoldersMap: array[TSpecialFolder] of Cardinal = ( CSIDL_DESKTOP,
    CSIDL_APPDATA, CSIDL_TEMPLATES, CSIDL_PROGRAMS, CSIDL_PERSONAL,
    CSIDL_FAVORITES, CSIDL_STARTUP, CSIDL_RECENT, CSIDL_SENDTO, CSIDL_STARTMENU,
    CSIDL_FONTS, CSIDL_HISTORY, CSIDL_COOKIES, CSIDL_INTERNET_CACHE,
    CSIDL_COMMON_FAVORITES, CSIDL_COMMON_DESKTOPDIRECTORY, CSIDL_COMMON_STARTUP,
    CSIDL_COMMON_PROGRAMS, CSIDL_COMMON_STARTMENU, 0, 0, 0, 0 );
var
  Res: Bool;
  Path: array[0..MAX_PATH-1] of Char;
  Reg: TRegistry;
begin
  Result := '';
  case Name of
    sfWindows: GetWindowsDirectory( Path, MAX_PATH );
    sfTemporary: GetTempPath( MAX_PATH, Path );
    sfSystem: GetSystemDirectory( Path, MAX_PATH );
    sfProgramFiles:
    begin
      Reg := TRegistry.Create( KEY_READ );
      try
        Reg.RootKey := HKEY_LOCAL_MACHINE;
        Reg.OpenKey( 'SOFTWARE\Microsoft\Windows\CurrentVersion', False );
        Result := AddSlash( Reg.ReadString( 'ProgramFilesDir' ) );
      finally
        Reg.Free;
      end;
      Exit;
    end;
  else
    Res := ShGetSpecialFolderPath( 0, Path, FoldersMap[ Name ], False );
    if not Res then
      raise Exception.Create( ClassName + '.GetSpecialFolder: Error on ShGetSpecialFolderPath' );
  end;
  Result := AddSlash( Path );
end;

function TPathParser.Parse(Path: string): string;
var
  S: string;
  I, I2, Pos: Integer;
begin
  I := 1;
  while I <= Length( Path )-3 do
  begin
    if ( Path[I] = '$' ) and ( Path[I+1] = '(' ) then
    begin
      I2 := I + 2;
      while ( I2 <= Length( Path ) ) and ( Path[I2] <> ')' ) do
        Inc( I2 );
      if I2 > Length( Path ) then
        Break;
      S := Copy( Path, I + 2, I2 - ( I + 2 ) );
      System.Delete( Path, I, I2 - I + 1 );
      Pos := IndexOfName( S );
      if Pos > -1 then
      begin
        System.Insert( ValueFromIndex[Pos], Path, I );
        Inc( I, Length( ValueFromIndex[Pos] ) );
      end
      else
        raise Exception.CreateFmt( '%s.Parse: Variável "%s" inexistente', [ ClassName, S ] ); //I := I2 + 1;
    end
    else
      Inc( I );
  end;
  Result := Path;
end;

end.

Recursive descent parser for Ruby - RDParser

A work of genius by Dennis Ranke (see original post at http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/174842 ). I want to keep this for posterity, but can't wait to see if this gets improved / extended, etc.

class RDParser
   attr_accessor :pos
   attr_reader :rules

   def initialize(&block)
     @lex_tokens = []
     @rules = {}
     @start = nil
     instance_eval(&block)
   end

   def parse(string)
     @tokens = []
     until string.empty?
       raise "unable to lex '#{string}" unless @lex_tokens.any? do |tok|
         match = tok.pattern.match(string)
         if match
           @tokens << tok.block.call(match.to_s) if tok.block
           string = match.post_match
           true
         else
           false
         end
       end
     end
     @pos = 0
     @max_pos = 0
     @expected = []
     result = @start.parse
     if @pos != @tokens.size
       raise "Parse error. expected: '#{@expected.join(', ')}', found 
'#{@tokens[@max_pos]}'"
     end
     return result
   end

   def next_token
     @pos += 1
     return @tokens[@pos - 1]
   end

   def expect(tok)
     t = next_token
     if @pos - 1 > @max_pos
       @max_pos = @pos - 1
       @expected = []
     end
     return t if tok === t
     @expected << tok if @max_pos == @pos - 1 && !@expected.include?(tok)
     return nil
   end

   private

   LexToken = Struct.new(:pattern, :block)

   def token(pattern, &block)
     @lex_tokens << LexToken.new(Regexp.new('\\A' + pattern.source), block)
   end

   def start(name, &block)
     rule(name, &block)
     @start = @rules[name]
   end

   def rule(name)
     @current_rule = Rule.new(name, self)
     @rules[name] = @current_rule
     yield
     @current_rule = nil
   end

   def match(*pattern, &block)
     @current_rule.add_match(pattern, block)
   end

   class Rule
     Match = Struct.new :pattern, :block

     def initialize(name, parser)
       @name = name
       @parser = parser
       @matches = []
       @lrmatches = []
     end

     def add_match(pattern, block)
       match = Match.new(pattern, block)
       if pattern[0] == @name
         pattern.shift
         @lrmatches << match
       else
         @matches << match
       end
     end

     def parse
       match_result = try_matches(@matches)
       return nil unless match_result
       loop do
         result = try_matches(@lrmatches, match_result)
         return match_result unless result
         match_result = result
       end
     end

     private

     def try_matches(matches, pre_result = nil)
       match_result = nil
       start = @parser.pos
       matches.each do |match|
         r = pre_result ? [pre_result] : []
         match.pattern.each do |token|
           if @parser.rules[token]
             r << @parser.rules[token].parse
             unless r.last
               r = nil
               break
             end
           else
             nt = @parser.expect(token)
             if nt
               r << nt
             else
               r = nil
               break
             end
           end
         end
         if r
           if match.block
             match_result = match.block.call(*r)
           else
             match_result = r[0]
           end
           break
         else
           @parser.pos = start
         end
       end
       return match_result
     end
   end
end


To use:

parser = RDParser.new do
   token(/\s+/)
   token(/\d+/) {|m| m.to_i }
   token(/./) {|m| m }

   start :expr do
     match(:expr, '+', :term) {|a, _, b| a + b }
     match(:expr, '-', :term) {|a, _, b| a - b }
     match(:term)
   end

   rule :term do
     match(:term, '*', :dice) {|a, _, b| a * b }
     match(:term, '/', :dice) {|a, _, b| a / b }
     match(:dice)
   end

   def roll(times, sides)
     (1..times).inject(0) {|a, b| a + rand(sides) + 1 }
   end

   rule :dice do
     match(:atom, 'd', :sides) {|a, _, b| roll(a, b) }
     match('d', :sides) {|_, b| roll(1, b) }
     match(:atom)
   end

   rule :sides do
     match('%') { 100 }
     match(:atom)
   end

   rule :atom do
     match(Integer)
     match('(', :expr, ')') {|_, a, _| a }
   end
end

puts "#{parser.parse(supply_string_here)}"

Space-Separated Tag Parser

Here is a function that accepts a string containing tags and returns an array of extracted tags. (Updated to ignore duplicates)
/**
 * Parses a String of Tags
 *
 * Tags are space delimited. Either single or double quotes mark a phrase.
 * Odd quotes will cause everything on their right to reflect as one single
 * tag or phrase. All white-space within a phrase is converted to single
 * space characters. Quotes burried within tags are ignored! Duplicate tags
 * are ignored, even duplicate phrases that are equivalent.
 *
 * Returns an array of tags.
 */
function ParseTagString($sTagString)
{
	$arTags = array();		// Array of Output
	$cPhraseQuote = null;	// Record of the quote that opened the current phrase
	$sPhrase = null;		// Temp storage for the current phrase we are building
	
	// Define some constants
	static $sTokens = " \r\n\t";	// Space, Return, Newline, Tab
	static $sQuotes = "'\"";		// Single and Double Quotes
	
	// Start the State Machine
	do
	{
		// Get the next token, which may be the first
		$sToken = isset($sToken)? strtok($sTokens) : strtok($sTagString, $sTokens);
		
		// Are there more tokens?
		if ($sToken === false)
		{
			// Ensure that the last phrase is marked as ended
			$cPhraseQuote = null;
		}
		else
		{		
			// Are we within a phrase or not?
			if ($cPhraseQuote !== null)
			{
				// Will the current token end the phrase?
				if (substr($sToken, -1, 1) === $cPhraseQuote)
				{
					// Trim the last character and add to the current phrase, with a single leading space if necessary
					if (strlen($sToken) > 1) $sPhrase .= ((strlen($sPhrase) > 0)? ' ' : null) . substr($sToken, 0, -1);
					$cPhraseQuote = null;
				}
				else
				{
					// If not, add the token to the phrase, with a single leading space if necessary
					$sPhrase .= ((strlen($sPhrase) > 0)? ' ' : null) . $sToken;
				}
			}
			else
			{
				// Will the current token start a phrase?
				if (strpos($sQuotes, $sToken[0]) !== false)
				{
					// Will the current token end the phrase?
					if ((strlen($sToken) > 1) && ($sToken[0] === substr($sToken, -1, 1)))
					{
						// The current token begins AND ends the phrase, trim the quotes
						$sPhrase = substr($sToken, 1, -1);
					}
					else
					{
						// Remove the leading quote
						$sPhrase = substr($sToken, 1);
						$cPhraseQuote = $sToken[0];
					}
				}
				else
					$sPhrase = $sToken;
			}
		}
		
		// If, at this point, we are not within a phrase, the prepared phrase is complete and can be added to the array
		if (($cPhraseQuote === null) && ($sPhrase != null))
		{
			$sPhrase = strtolower($sPhrase);
			if (!in_array($sPhrase, $arTags)) $arTags[] = $sPhrase;
			$sPhrase = null;
		}
	}
	while ($sToken !== false);	// Stop when we receive FALSE from strtok()
	return $arTags;
}


The string can be recreated from the array with the use of this reverse function:
/**
 * Reverses ParseTagString()
 */
function CreateTagString($arTags)
{
	// Prepare each tag to be imploded
	for ($i = 0; $i < sizeof($arTags); $i++)
	{
		// Record findings
		$bContainsWhitespace = false;	// Was whitespace found?
		$cRequiredQuote = '"';			// Use double-quote by default
		$cLastChar = null;
	
		// Search the tag
		for ($j = 0; $j < strlen($arTags[$i]); $j++)
		{
			$c = $arTags[$i][$j];
			
			// If the current character is a space
			if ($c === ' ')
			{
				$bContainsWhitespace = true;
				
				// If the previous char was a double quote, we require single quotes round our phrase
				if ($cLastChar === '"')
				{
					$cRequiredQuote = "'";
					break;	// There is no more point in continuing our search, we cant handle double-mixed quotes
				}
			}
			
			// Record this char as the last char
			$cLastChar = $c;
		}
		
		// Quote if necessary
		if ($bContainsWhitespace) $arTags[$i] = $cRequiredQuote . $arTags[$i] . $cRequiredQuote;
	}
	return implode(' ', $arTags);
}


To test the whole system, use the following array of test cases:
$arTestInputs = array(
	"this test ensures that words are correctly split",
	"in this test \"phrases\" and \"multi-word phrases\" are tested",
	"this test shows the behaviour if an \"odd quote is detected",
	"this test shows that 'different quotes' work too",
	"but mixed quotes fail: \"test phrase' does not stop on the quote",
	"which can be usefull in some cases where \"the systems' requirements\" state that it is necessary",
	"quotes need not be attached to \" their phrase \"",
	"embedded\"quotes are ignored!",
	"this is also usefull and demonstrates the system's coolness",
	"redundant   white-space is   removed from \"  tags    and phrases\"",
	"\"\"double quotes\"\" will result in single quotes!",
	"remember that 'double-quotes\" may be nested within single quotes'",
	"TaGs ArE NOT case SENsITiVE!",
	"a duplicate tag will be removed from the tag list",
	"even a \" complex phrase\" that is equivalent to another 'compleX   PHrASe   '"
);

foreach ($arTestInputs as $sTest)
{
	print ("<pre>$sTest</pre>");
	print "<pre>";
	print_r (ParseTagString($sTest));
	print "</pre>";
	print "<pre>";
	print CreateTagString(ParseTagString($sTest));
	print "</pre>";
	print "<hr />";
}


2006-03-09 0.1.0 - 0.2.0 Duplicate phrases are now ignored.

--
Version 0.2.0 - 2006-03-09
STEM: The STEM Cells of PHP
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License
http://creativecommons.org/licenses/by-sa/2.5/

Binary Data Parser //Javascript Class



This is a prototyped class written to serialize and unserialize binary data, so you can read and write binary data files to exchange with programs written in languages like C and Pascal.

Currently the class is able to handle just the following types: signed integers (small 8 bits, short 16 bits, int 32 bits), unsigned integers (byte 8 bits, word 16 bits, dword 32 bits) and floating point (IEEE754 float 32 bits and double 64 bits).

The endianess of the binary values representation can also be configured with the class.

[UPDATED CODE AND HELP CAN BE FOUND HERE]


There's a php version right here.

Code

//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/binary-parser [v1.0]

BinaryParser = function( bigEndian, allowExceptions ){
	this.bigEndian = bigEndian;
	this.allowExceptions = allowExceptions;
};
with( { p: BinaryParser.prototype } ){
	with( {p: ( p.Buffer = function( bigEndian, buffer ){ this.bigEndian = bigEndian || 0; this.buffer = []; this.setBuffer( buffer ); } ).prototype } ){
		p.setBuffer = function( data ){
			if( data ){
				for( var l, i = l = data.length, b = this.buffer = new Array( l ); i; b[l - i] = data.charCodeAt( --i ) );
				this.bigEndian && b.reverse();
			}
		};
		p.hasNeededBits = function( neededBits ){
			return this.buffer.length >= -( -neededBits >> 3 );
		};
		p.checkBuffer = function( neededBits ){
			if( !this.hasNeededBits( neededBits ) )
				throw new Error( "checkBuffer::missing bytes" );
		};
		p.readBits = function( start, length ){
			//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
			function shl( a, b ){
				for( ; b--; a = ( ( a %= 0x7fffffff + 1 ) & 0x40000000 ) == 0x40000000 ? a * 2 : ( a - 0x40000000 ) * 2 + 0x7fffffff + 1 );
				return a;
			}
			if( start < 0 || length <= 0 )
				return 0;
			this.checkBuffer( start + length );
			for( var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - ( start >> 3 ) - 1, lastByte = this.buffer.length + ( -( start + length ) >> 3 ), diff = curByte - lastByte, sum = ( ( this.buffer[ curByte ] >> offsetRight ) & ( ( 1 << ( diff ? 8 - offsetRight : length ) ) - 1 ) ) + ( diff && ( offsetLeft = ( start + length ) % 8 ) ? ( this.buffer[ lastByte++ ] & ( ( 1 << offsetLeft ) - 1 ) ) << ( diff-- << 3 ) - offsetRight : 0 ); diff; sum += shl( this.buffer[ lastByte++ ], ( diff-- << 3 ) - offsetRight ) );
			return sum;
		};
	}
	p.warn = function( msg ){
		if( this.allowExceptions )
			throw new Error( msg );
		return 1;
	};
	p.decodeFloat = function( data, precisionBits, exponentBits ){
		var b = new this.Buffer( this.bigEndian, data );
		b.checkBuffer( precisionBits + exponentBits + 1 );
		var bias = Math.pow( 2, exponentBits - 1 ) - 1, signal = b.readBits( precisionBits + exponentBits, 1 ), exponent = b.readBits( precisionBits, exponentBits ), significand = 0,
		divisor = 2, curByte = b.buffer.length + ( -precisionBits >> 3 ) - 1;
		do
			for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
		while( precisionBits -= startBit );
		return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
	};
	p.decodeInt = function( data, bits, signed ){
		var b = new this.Buffer( this.bigEndian, data ), x = b.readBits( 0, bits ), max = Math.pow( 2, bits );
		return signed && x >= max / 2 ? x - max : x;
	};
	p.encodeFloat = function( data, precisionBits, exponentBits ){
		var bias = Math.pow( 2, exponentBits - 1 ) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits,
		status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0,
		exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ),
		signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart,
		i, lastBit, rounded, j, result;
		for( i = len; i; bin[--i] = 0 );
		for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) );
		for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart );
		for( i = -1; ++i < len && !bin[i]; );
		if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){
			if( !( rounded = bin[lastBit] ) )
				for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] );
			for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) );
		}
		for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; );
		if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp )
			++i;
		else if( exp < minExp ){
			exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" );
			i = bias + 1 - ( exp = minExp - 1 );
		}
		if( intPart || status !== 0 ){
			this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status );
			exp = maxExp + 1;
			i = bias + 2;
			if( status == -Infinity )
				signal = 1;
			else if( isNaN( status ) )
				bin[i] = 1;
		}
		for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 );
		for( n = 0,