Use PHP functions in JavaScript

Add Function

No expertise needed. Just JS Coding skills. We will review the code and make the changes in SVN. When your code makes it into php.js you will be credited accordingly.

Add a comment with your code at the bottom of this page.

If you want you can read the Developer Guidelines that would save us some work.

Function proposals

Add Comment
Use:
[CODE]
your_stuff('here');
[/CODE]
for proper code formatting
By submitting code here you are allowing us to use it in php.js hence dual licensing it under the MIT and GPL licenses

Gravatar
Marco Marchiò
17 Dec '09 Permalink

q  @Brett/Kevin: Harmony is a very interesting project and it's a good starting point. I think that i will start from converting it to js to parse the php code. Anyway now it's christmas time (also in Italy:D) and i don't like to work when there is the snow so i'm going to start in the 2010:D. Merry christmas and happy new year to everybody.

Gravatar
Brett Zamir
14 Dec '09 Permalink

q  @Kevin/Marco: As far as the Harmony Framework, while that can be pretty cool, that is making use of tokenizer on the server-side, while our intention is to implement that part in JavaScript also. Nevertheless, it may still be of interest.

Gravatar
Brett Zamir
14 Dec '09 Permalink

q  @Kevin: I have to agree, this looks like very good stuff (Just to check though, did you mean to redefine the variable 'i' within a loop which already was using 'i'?).

I think Tim's way with undefined is the best way though, as he is testing with "typeof". One advantage to this is that it is immune to "undefined" itself being redefined as JavaScript oddly allows. Also, if you test against undefined itself AND use a typeof, you will never get a true result because typeof always returns a string. Fixed in Git.

Gravatar
Kevin van Zonneveld
14 Dec '09 Permalink

q  @ Tim de Koning: Brilliant stuff Tim, I must say. I've added your function to our repo: http://github.com/kvz/phpjs/commit/ad6df4d48a7551b2ddc53bf03c464bdf1d49b8e4 and hence will be online shortly.

I already fixed some common jslint issues: http://github.com/kvz/phpjs/commit/5cb72f3bd9c6b624827193a2bfde24de14c0ab32 but there are still some more to tackle.

You asked for feedback; one thing I would to see - if possible - is more orthodox for-loops. You seem to perform a lot of calculations in the header of a forloop while it may just as well be possible to do them in the body.
This would allow for less jslint errors, shorter lines, and hence improved readability & maintainability.
I also noticed you check for undefined with == 'undefined'. The correct way is === undefined: this will save you some headaches to come.

There's an interesting webcast by Douglass Crockford to be found in the Developer Guidelines here: http://wiki.github.com/kvz/phpjs/developerguidelines

It's related to a lot of my points above.

Anyway, please don't feel discouraged here, I'm just trying to help you write even better JavaScript. As for your contribution: pack is a wonderful new member to php.js' arsenal. Thanks so much!

Gravatar
Kevin van Zonneveld
14 Dec '09 Permalink

q  @ Marco Marchiò: Be sure to also checkout the Harmony Framework http://www.harmony-framework.com/

Gravatar
Tim de Koning
12 Dec '09 Permalink

q  

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
152
153
154
155156
157
158
159
160161
162
163
164
165166
167
168
169
170171
172
173
174
175176
177
178
179
180181
182
183
184
185186
187
188
189
190191
192
193
194
195196
197
198
199
200201
202
203
204
205206
207
208
209
210211
function pack(format) {
        // Pack given arguments into binary string according to format.
    // For possible formats see  http://www.php.net/pack
    //
    // Please note: 'machine dependant byte order and size' aren't applicable for javascript        // pack works as on a 32bit, little endian machine 
    //
    // version: 0.1
    // discuss at: http://www.kingsquare.nl/blog/12-12-2009/13507444/New-phpjs-function-pack-
    // dependancies: none    // + original by: Tim de Koning (http://www.kingsquare.nl)
    // + original float encoding by: Jonas Raoni Soares Silva (http://jsfromhell.com/classes/binary-parser) 
    //
    // * example 1: pack("nvc*", 0x1234, 0x5678, 65, 66);
    // *     returns 1: '4xVAB';        //
        // feedback is nice :-) phpjs-pack@kingsquare.nl
 
        var formatPointer, argumentPointer, result, instruction, quantifier, word, nibble;
         formatPointer = 0;
        argumentPointer = 1;
        result = '';
 
        while (formatPointer < format.length) {                instruction = format[formatPointer];
                quantifier = '';
                formatPointer++;
                while((formatPointer < format.length) && (format[formatPointer].match(/[0-9\*]/) != null)) {
                        quantifier += format[formatPointer];                        formatPointer++;
                }
                if (quantifier == '') quantifier = 1;
                //now pack variables: 'quantifier' times 'instruction'
                switch(instruction) {                        case 'A': //NUL-padded string
                        case 'a': //SPACE-padded string
                                if (typeof arguments[argumentPointer] == 'undefined') throw new Error('Warning:  pack() Type '+instruction+': not enough arguments');
                                else argument = arguments[argumentPointer];
                                if (quantifier=='*') quantifier = argument.length;                                for (var i=0; i<quantifier; i++) {
                                        if (typeof argument[i] == 'undefined') {
                                                if (instruction == 'a') result += "\0";
                                                else result += " ";
                                        }                                        else result += argument[i];
                                }
                                argumentPointer++;
                                break;
                         case 'h': //Hex string, low nibble first
                        case 'H': //Hex string, high nibble first
                                if (typeof arguments[argumentPointer] == 'undefined')  throw new Error( 'Warning:  pack() Type '+instruction+': not enough arguments');
                                else argument = arguments[argumentPointer];
                                if (quantifier=='*') quantifier = argument.length;                                if (quantifier > argument.length) throw new Error('Warning: pack() Type '+instruction+': not enough characters in string');
                                for (var i=0; i<quantifier; i+=2) {
                                        //always get per 2 bytes...
                                        word = argument[i];
                                        if (((i+1) >= quantifier) || typeof(argument[i+1])=='undefined') { word += "0"; }                                        else word += argument[i+1];
                                        //the fastest way to reverse?
                                        if (instruction == 'h') word = word[1]+word[0];
                                        result += String.fromCharCode(parseInt(word, 16));
                                }                                argumentPointer++;
                                break;
 
                        case 'c': //signed char
                        case 'C': //unsigned char                                //c and C is the same in pack
                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
 
                                for (var i=0; i<quantifier; i++) {                                        result += String.fromCharCode(arguments[argumentPointer]);
                                        argumentPointer++
                                }
                                break;
                          case 's': // signed short (always 16 bit, machine byte order)
                         case 'S': // signed short (always 16 bit, machine byte order)
                         case 'v':
                                //s and S is the same in pack
                                //but can machine byte order be retrieved in javascript?                                //this is default byte order anywayz...
                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
 
                                for (var i=0; i<quantifier; i++) {                                        result += String.fromCharCode(arguments[argumentPointer]&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
                                        argumentPointer++;
                                }
                                break; 
                         case 'n': // unsigned short (always 16 bit, big endian byte order)
                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
                                 for (var i=0; i<quantifier; i++) {
                                        result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]&0xFF);
                                        argumentPointer++;
                                }                                break;
 
                         case 'i': // signed integer (machine dependent size and byte order)
                         case 'I': // unsigned integer (machine dependent size and byte order)
                         case 'l': // signed long (always 32 bit, machine byte order)                         case 'L': // unsigned long (always 32 bit, machine byte order)
                         case 'V': // unsigned long (always 32 bit, little endian byte order)
                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
                                 for (var i=0; i<quantifier; i++) {
                                        result += String.fromCharCode(arguments[argumentPointer]&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]>>16&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]>>24&0xFF);                                        argumentPointer++;
                                }
 
                                break;
                         case 'N': // unsigned long (always 32 bit, big endian byte order)                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
 
                                for (var i=0; i<quantifier; i++) {
                                        result += String.fromCharCode(arguments[argumentPointer]>>24&0xFF);                                        result += String.fromCharCode(arguments[argumentPointer]>>16&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]>>8&0xFF);
                                        result += String.fromCharCode(arguments[argumentPointer]&0xFF);
                                        argumentPointer++;
                                }                                break;
 
                         case 'f': // float (machine dependent size and representation)
                         case 'd': // double (machine dependent size and representation)
                                //version based on IEEE754y 
                                var precisionBits = 23, exponentBits = 8;
                                if (instruction=='d') {
                                        precisionBits = 52 ;
                                        exponentBits = 11;                                }
 
                                if (quantifier=='*') quantifier = arguments.length - argumentPointer;
                                if (quantifier > (arguments.length - argumentPointer))  throw new Error('Warning:  pack() Type '+instruction+': too few arguments');
                                for (var i=0; i<quantifier; i++) { 
                                        var number = arguments[argumentPointer], bias = Math.pow(2, exponentBits - 1) - 1, minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits, status = isNaN(n = parseFloat(number)) || 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, tmpResult;
                                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];);
                                (exp = bias + 1 - i) >= minExp && exp <= maxExp ? ++i : exp < minExp && (exp != bias + 1 - len && exp < minUnnormExp, i = bias + 1 - (exp = minExp - 1));
                                (intPart || status !== 0) && (1, exp = maxExp + 1, i = bias + 2, status == -Infinity ? signal = 1 : isNaN(status) && (bin[i] = 1));                                for(n = Math.abs(exp + bias), j = exponentBits + 1, tmpResult = ""; --j; tmpResult = (n % 2) + tmpResult, n = n >>= 1);
                                for(n = 0, j = 0, i = (tmpResult = (signal ? "1" : "0") + tmpResult + bin.slice(i, i + precisionBits).join("")).length, r = []; i; n += (1 << j) * tmpResult.charAt(--i), j == 7 && (r[r.length] = String.fromCharCode(n), n = 0), j = (j + 1) % 8);
                                r[r.length] = n ? String.fromCharCode(n) : "";
                                result += r.join('');
                                        argumentPointer++;                                }
                                break;
 
                        case 'x': //NUL byte
                                if (quantifier=='*') throw new Error('Warning: pack(): Type x: \'*\' ignored');                                for (var i=0; i<quantifier; i++) {
                                        result += "\0";
                                }
                                break;
                         case 'X': //Back up one byte
                                if (quantifier=='*') throw new Error('Warning: pack(): Type X: \'*\' ignored');
                                for (var i=0; i<quantifier; i++) {
                                        if (result.length==0) {
                                                 throw new Error('Warning: pack(): Type X: outside of string');                                        } else {
                                                result = result.substring(0, result.length - 1);
                                        }
                                }
                                break; 
                        case '@': //NUL-fill to absolute position
                                if (quantifier=='*') throw new Error('Warning: pack(): Type X: \'*\' ignored');
                                if (quantifier>result.length) {
                                        var extraNullCount = quantifier - result.length;                                        for (var i=0; i<extraNullCount; i++) {
                                                result += "\0";
                                        }
                                }
                                if (quantifier<result.length) {                                        result = result.substring(0, quantifier);
                                }
                                break;
 
                        default:                                throw new Error('Warning:  pack() Type '+instruction+': unknown format code')
                }
        }
        if (argumentPointer < arguments.length) throw new Error('Warning: pack(): '+( arguments.length - argumentPointer)+' arguments unused');
        return result;}

Gravatar
Paul Hutchinson
2 Dec '09 Permalink

q  @Brett Zamir: Thanks for the tip Brett.

Gravatar
Marco Marchiò
2 Dec '09 Permalink

q  @Brett: interesting links:) right now I've a lot of work to do but when I have time i will try to do that.

Gravatar
Brett Zamir
2 Dec '09 Permalink

q  @Marco, I've been trying to work on one myself, so I think a PHP-in-JavaScript parser is a great idea. :) (We could build it as the function token_get_all() as in the real PHP tokenizer extension.)

Among other things, it'd be great to have it to convert the PHP unit tests into php.js unit tests.

I figured it may be even cooler to parse a standard syntax like EBNF (see Wikipedia) so we could create parsers/lexers for any language which was defined in EBNF.

I found an EBNF grammar at http://www.icosaedro.it/articoli/php-syntax-ebnf.txt

I started playing around with it, then discovered Antlr, which is already meant to do this, and has a JavaScript implementation.

However, it is not documented with a lot of examples (see http://www.antlr.org/wiki/display/ANTLR3/ANTLR3JavaScriptTarget ), though there is a whole lot to read about it (http://www.antlr.org/wiki/display/ANTLR3/ANTLR+v3+printable+documentation or the tutorials at http://www.antlr.org/wiki/display/ANTLR3/Tutorials

I tried out the Expression Evaluator tool they have (see http://www.antlr.org/works/help/tutorial/calculator.html ) for download against the PHP EBNF, but after converting to a format the software recognized, I ran into some errors about parts of the EBNF being defined recursively, and I haven't had a chance to figure out how it could be resolved.

In other words, this could take a lot of time, but it would be soooo worth it if someone is interested to help out or try it out themselves.

Everything from syntax highlighters, to translators, etc. would be possible. And of course, it'd be cool to have one for JavaScript itself, though JSLint may already be a good one to use for that...

Gravatar
Marco Marchiò
1 Dec '09 Permalink

q  @Brett: what do you think about creating a php parser written in javascript, so that you can use the PHP sintax (especially classes) to generate the relative js code?

Gravatar
Brett Zamir
30 Nov '09 Permalink

q  By the way, if anyone has any outstanding issues (besides the recent items for date() which I've already added to our tracker, and besides the error_log() and asort() issues which I have on my todo list), please let us know so we can try to make sure we are 100% tracking all outstanding issues...

Gravatar
Brett Zamir
30 Nov '09 Permalink

q  @Kankrelune : Doesn't look like I told you that I added your reimplementation for version_compare... Thanks!

Gravatar
Brett Zamir
29 Nov '09 Permalink

q  @Paul: That sounds like a good idea. I'd like to take a closer look when I have some time. As far as file writing, I've started a "file_put_contents()" implementation for use in Mozilla extensions, but we can adapt it to alternatively work for making Ajax POST or PUT requests (as well as make it work with CommonJS SSJS potentially too). We can use the stream context argument to do any configuration (e.g., to work with Mozilla file writing instead of Ajax POST or whatever).

Btw, one JavaScript gotcha to look out for (at least for us PHP devs) is that you can't test for "console" as you did; if it doesn't exist, it will cause an error that causes the script to stop. You either have to make the check as a try-catch block, or test it as a property (i.e., "if (window.console) ...").

Gravatar
Paul Hutchinson
26 Nov '09 Permalink

q   Most browsers now support basic console.log() so it would be helpful to output error_log() to this.

I don't see a way to support email or file logging, but basic console.log() would be a good start.

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
function error_log(message,message_type,destination,extra_headers)
{
    if(typeof(console) === 'undefined' || console == null)
        return;
     if(message_type==null)
        message_type=0;
    switch(message_type)
    {
        case 0: // console        case 4: // SAPI logging
            console.log(message);
        break;
        case 1: // email
            console.log(message);        break;
        case 2: // nothing
        break;
        case 3: // file logging
            if(console.group!=null)                console.group(destination);
            console.log(message);
            if(console.groupEnd!=null)
                console.groupEnd();
        break;    }
}

Gravatar
Brett Zamir
20 Nov '09 Permalink

q  Also please note I just made another commit now which removed a trailing comma (needed for IE) in the initial OPTS assignment.

Gravatar
Brett Zamir
20 Nov '09 Permalink

q  Hi Marco,

Ok, now looks great, thanks! I added a couple other test cases and they passed too. I also added some code toward the beginning to allow flags to be passed in as bitwise-OR'd numbers, a single-item string, or an array of strings (yours allowed multiple flags to be space-separated in a single string, but to avoid potential conflicts, I think we should stick with arrays and bitwise-OR'd numbers for this). The commit is at http://github.com/kvz/phpjs/commit/9e36e6a87aae3cbfbeb98890a2775d479297d735

However, it's up to Kevin as to whether this should be moved to the main /functions directory (and category) at this point since our preg functions do not support all of the flags and syntax of PHP regular expressions such as Unicode character classes as in a good many cases these could in fact be added, such as in the very good XRegExp package.

We could just release the preg functions for now as long as they implement all of the function arguments (at least preg_split() already does) and just hope that they will later be improved to support more of the PCRE syntax and flags.

Gravatar
Marco Marchiò
19 Nov '09 Permalink

q   @Brett: i've finally solved the problem and correct another bug. Now every test works.

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
function preg_split (pattern, subject, limit, flags) {
    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: [hypertext, language, programming]    // * example 2: preg_split('//', 'string', -1, 'PREG_SPLIT_NO_EMPTY');
    // * returns 2:
    // * example 3: var str = 'hypertext language programming';
    // * example 3: preg_split('/ /', str, -1, 'PREG_SPLIT_OFFSET_CAPTURE');
    // * returns 3: 
// First example still causing infinite loop!
 
    limit = limit || 0; flags = flags || ''; // Limit and flags are optional
    var result, ret=[], index=0, i = 0,        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,
        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
        regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1],
        regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];        // Non-global regexp causes an infinite loop when executing the while,
        // so if it's not global, copy the regexp and add the "g" modifier.
        pattern=pattern.global && typeof pattern!="string" ? pattern :
            new RegExp(regexpBody, regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":"g"));
    var _filter = function(str,strindex) {        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}
        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}        ret.push(str);
    };
    //Special case for empty regexp
    if(!regexpBody){
        result=subject.split("");        for(i=0;i<result.length;i++) {
            _filter(result[i],i);
        }
        return ret;
    }    // Exec the pattern and get the result
    while(result = pattern.exec(subject)) {
        // Stop if the limit is 1
        if (limit === 1) {break;}
        // Take the correct portion of the string and filter the match        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;
        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {
            // Convert the regexp result into a normal array            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {
                    _filter(result[i], result.index+result[0].indexOf(result[i]));
                }            }
        }
        limit--;
    }
    // Filter last match    _filter(subject.slice(index, subject.length), index);
    return ret;
}

Gravatar
Brett Zamir
18 Nov '09 Permalink

q   @Marco: Here ya go... (Btw, I'd debug it myself, but busy and have a cold)

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
<script>
 
alert(preg_split(/[\s,]+/, "hypertext language, programming"));
 
function preg_split (pattern, subject, limit, flags) {    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: 'hypertext,language,programming' 
    limit = limit || 0; flags = flags || ''; //Limit and flags are optional    var result, ret=[], index=0, i = 0,
        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,
        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
                regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1],                 regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];
                //non global regexp cause a infinite loop when executing the while,
                //so if it's not global copy the regexp and add the "g" modifier.
                pattern=pattern.global || typeof pattern!="string" ? pattern : 
                                new RegExp(regexpBody,regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":regexpFlags+"g"));            var _filter = function(str,strindex) {
        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}        ret.push(str);
    };        
        //Special case for empty regexp
        if(!regexpBody){
                var result=subject.split("");                for(i=0;i<result.length;i++) _filter(result[i],i);
                return ret;        }
    // Exec the pattern and get the result
var ctr=0;
    while(result = pattern.exec(subject)) {    if (++ctr > 100) {break;}
        // Stop if the limit is 1
        if (limit === 1) {break;}        // Take the correct portion of the string and filter the match
        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {            // Convert the regexp result into a normal array
            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {                    _filter(result[i], result.index+result[0].indexOf(result[i]));                }
            }
        }
        limit--;
    }    // Filter last match
    _filter(subject.slice(index, subject.length), index);
    return ret;
}
 </script>

Gravatar
Marco Marchiò
18 Nov '09 Permalink

q  @Brett: I've done every test again in Firefox, IE7, IE6, Opera, Chrome and Safari and i haven't found any infinite loop. This time i have taken the copy of the function from github so it's correct. I'm sorry but i can't get the error you're talking about. Can you write the code that you use when you get the infinite loop?

Gravatar
Brett Zamir
18 Nov '09 Permalink

q  @Marco: I am using the exact code you have below in Firefox, and it will run into an infinite loop with the first example you have listed there... Is it possible something was stripped out of your code by our comments system--if you test in Firefox against that code as it is there, you should see it also creates an infinite loop (though I'd put a limit in the while loop so your browser doesn't lock up)...

Gravatar
Marco Marchiò
17 Nov '09 Permalink

q  @Brett: i've done all tests with the last function that i've posted and they are all correct, so please try again. Remember that in js when you pass a string as a regex you must use the double escape char ( \s become \\s ), maybe you forgot it when you have done your tests because i don't get any error and i don't understand why you still getting an infinite loop.

Gravatar
Brett Zamir
15 Nov '09 Permalink

q  @Marco: I'm still getting infinite loops on the first example. Please test all tests and make sure all three are working. If you are using Firefox, I would suggest https://addons.mozilla.org/en-US/firefox/addon/7434 and its XUL Editor or JS Env for doing JavaScript tests . Also, I'm not sure why, but the line returns are getting messed up--is that something you are doing or is the comment code at this site? Also, please use http://github.com/kvz/phpjs/blob/master/_workbench/pcre/preg_split.js . Thanks!

Gravatar
Marco Marchiò
13 Nov '09 Permalink

q   @Brett Zamir: I've fixed the infinite loop bug and done other tests. I think it works perfect now.

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
function preg_split (pattern, subject, limit, flags) {
    // http://kevin.vanzonneveld.net
    // + original by: Marco Marchi?
    // * example 1: preg_split(/[\s,]+/, "hypertext language, programming");
    // * returns 1: 'hypertext,language,programming' 
    limit = limit || 0; flags = flags || ''; //Limit and flags are optional
    var result, ret=[], index=0, i = 0,
        noEmpty = flags.indexOf("PREG_SPLIT_NO_EMPTY") !== -1,
        delim = flags.indexOf("PREG_SPLIT_DELIM_CAPTURE") !== -1,        offset = flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE") !== -1,
                regexpBody=/^\/(.*)\/\w*$/.exec(pattern.toString())[1], 
                regexpFlags=/^\/.*\/(\w*)$/.exec(pattern.toString())[1];
                //non global regexp cause a infinite loop when executing the while,
                //so if it's not global copy the regexp and add the "g" modifier.                pattern=pattern.global || typeof pattern!="string" ? pattern : 
                                new RegExp(regexpBody,regexpFlags+(regexpFlags.indexOf("g")!==-1 ? "":regexpFlags+"g"));        
    var _filter = function(str,strindex) {
        // If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set don't add it
        if(noEmpty && !str.length) {return;}        // If the PREG_SPLIT_OFFSET_CAPTURE flag is set
        // transform the match into an array and add the index at position 1
        if(offset) {str = [str,strindex];}
        ret.push(str);
    };        //Special case for empty regexp
        if(!regexpBody){
                var result=subject.split("");
                for(i=0;i<result.length;i++) _filter(result[i],i);
                return ret;        }
    // Exec the pattern and get the result
    while(result = pattern.exec(subject)) {
        // Stop if the limit is 1
        if (limit === 1) {break;}        // Take the correct portion of the string and filter the match
        _filter(subject.slice(index, result.index), index);
        index = result.index+result[0].length;
        // If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
        if(delim) {            // Convert the regexp result into a normal array
            var resarr = Array.prototype.slice.call(result);
            for(i = 1; i < resarr.length; i++) {
                if(result[i] !== undefined) {
                    _filter(result[i], result.index+result[0].indexOf(result[i]));                }
            }
        }
        limit--;
    }    // Filter last match
    _filter(subject.slice(index, subject.length), index);
    return ret;
}

Gravatar
Brett Zamir
11 Nov '09 Permalink

q   @Marco: Not yet. Getting another infinite loop trying the second example:

1
preg_split('//', 'string', -1, 'PREG_SPLIT_NO_EMPTY');


Maybe it's because it's empty, haven't looked carefully at it.

Here's the third one to try too:

1
2
var str = 'hypertext language programming';
var chars = preg_split('/ /', str, -1, 'PREG_SPLIT_OFFSET_CAPTURE');


and make sure it follows that in the docs at http://www.php.net/manual/en/function.preg-split.php

Please, if you would, use this version to work off of in the future since I cleaned it up a little superficially:
http://github.com/kvz/phpjs/blob/master/_workbench/pcre/preg_split.js

Thanks!

Gravatar
Brett Zamir
9 Nov '09 Permalink

q  @Ben Shelock: That was a nice attempt for someone who describes themselves as an amateur, so thanks for offering! However, in order to emulate the function PHP fully, which allows special treatment of C-escape sequences, which sometimes makes octal escapes, and allows ranges of characters, there is a good bit more which needed to be done. I had already begun an implementation on this earlier, and it is now finished at http://github.com/kvz/phpjs/blob/master/functions/strings/addcslashes.js thanks to your prompting... :)

Gravatar
Marco Marchiò
9 Nov '09 Permalink

q   Fixed the infinite loop bug:

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
function preg_split(pattern,subject,limit,flags)
{
        var limit=limit || 0, flags=flags || "", //Limit and flags are optional
        result, ret=new Array(), index=0,
                //non global regexp cause a infinite loop when executing the while,                //so if it's not global copy the regexp and add the "g" modifier
                pattern=pattern.global? pattern : new RegExp(/^\/(.*)\/\w*$/.exec(pattern.toString())[1],/^\/.*\/(\w*)$/.exec(pattern.toString())[1]+"g"),
        noEmpty=flags.indexOf("PREG_SPLIT_NO_EMPTY")!=-1,        delim=flags.indexOf("PREG_SPLIT_DELIM_CAPTURE")!=-1,
        offset=flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE")!=-1,
        filter=function(str,strindex){                        //If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set dont'add it
                        if(noEmpty && !str.length) return; 
                        //If the PREG_SPLIT_OFFSET_CAPTURE flag is set transform the match into an array and add the index at position 1                        
                        if(offset) str=new Array(str,strindex);
                        ret.push(str);        };
        //Exec the pattern and get the result        
                while(result=pattern.exec(subject)) {
                        //Stop if the limit is 1
                        if(limit==1) break;                        //Take the correct portion of the string and filter the match
                        filter(subject.slice(index,result.index),index);               
                        index=result.index+result[0].length;
                        //If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
                        if(delim)                        {
                                        //Convert the regexp result into a normal array                        
                                        var resarr=Array.prototype.slice.call(result);
                                        for(i=1;i<resarr.length;i++)
                                                        if(result[i]!==undefined) filter(result[i],result.index+result[0].indexOf(result[i]));                                          }
                        limit--;        
                }
        //Filter last match
        filter(subject.slice(index,subject.length),index);        return ret;
}

Gravatar
Marco Marchiò
9 Nov '09 Permalink

q  @Brett Zamir: I can't see the test but when i have done my tests i remember that i found that bug too, but it's not an error in the code. It is produced by regexp that are not global (no G modifier), with those regexp the while loop become infinite. I try to solve the problem now.

Gravatar
Ben Shelock
9 Nov '09 Permalink

q  

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
function addcslashes(str, charlist){
    // Escapes characters defined in charlist
    // 
    // version: 1
    // discuss at: http://phpjs.org/functions/addcslashes    // +   original by: Ben Shelock
    // %        note 1: Developed by a javascript amature, forgive me.
    // *     example 1: addcslashes('Something', 'oei');
    // *     returns 1: S\om\eth\ing
     var charlist = charlist.split(""), string = '';
    for(var i = 0; i < str.length; i++){
        if(in_array(str[i], charlist)){
            string = string+'\\'+str[i];
        }        else{
            string = string+str[i];
        }
    }
    return string;}

Gravatar
Brett Zamir
7 Nov '09 Permalink

q  @Marco: Thanks for the function (it would be a great one to have), and I added it to our workbench area, but it looks like there is still at least one bug needing fixing. If you use the example I added at http://github.com/kvz/phpjs/blob/8f2086ef2577bc81486a3f96d6a850e2b2d82b03/_workbench/pcre/preg_split.js it runs in an infinite loop.

Gravatar
Marco Marchiò
5 Nov '09 Permalink

q  

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
35
function preg_split(pattern,subject,limit,flags)
{
        var limit=limit || 0, flags=flags || "", //Limit and flags are optional
        result, ret=new Array(), index=0,
        noEmpty=flags.indexOf("PREG_SPLIT_NO_EMPTY")!=-1,        delim=flags.indexOf("PREG_SPLIT_DELIM_CAPTURE")!=-1,
        offset=flags.indexOf("PREG_SPLIT_OFFSET_CAPTURE")!=-1,
        filter=function(str,strindex){
                //If the match is empty and the PREG_SPLIT_NO_EMPTY flag is set dont'add it
                if(noEmpty && !str.length) return;                //If the PREG_SPLIT_OFFSET_CAPTURE flag is set transform the match into an array and add the index at position 1
                if(offset) str=new Array(str,strindex);
                ret.push(str);
        };
        //Exec the pattern and get the result        while(result=pattern.exec(subject)) {
                //Stop if the limit is 1
                if(limit==1) break;
                //Take the correct portion of the string and filter the match
                filter(subject.slice(index,result.index),index);                index=result.index+result[0].length;
                //If the PREG_SPLIT_DELIM_CAPTURE flag is set every capture match must be included in the results array
                if(delim)
                {
                        //Convert the regexp result into a normal array                        var resarr=Array.prototype.slice.call(result);
                        for(i=1;i<resarr.length;i++)
                                if(result[i]!==undefined) filter(result[i],result.index+result[0].indexOf(result[i]));                  
                }
                limit--;        }
        //Filter last match
        filter(subject.slice(index,subject.length),index);
        return ret;
}

Gravatar
Brett Zamir
29 Jun '09 Permalink

q  Ok, it is now added in SVN and passing all tests. Thanks very much for this one!

Gravatar
Greg Frazier
26 Jun '09 Permalink

q   Honestly, I wrote this function several months ago for a project and discovered it would be easier if I implemented it in PL/SQL. I recently found it in some old files, tested it using the same test that Apache uses for their metaphone function and fixed any errors that I found (passes 238 tests out of 244, although PHP's implementation isn't without errors either)
I have it up here if you want to see it: http://gregoryfrazier.com/metaphone2.html

When I wrote it, I spent very little time on it, it's quite a hack job, thats why I'm saying I'm sure there are bugs. I don't know when I'd have time next to debug it; so I thought I'd just post it up here for someone else to look at and play around with, or else it would just rot on my hard drive.

As for the String() question, I vaguely remember something about Internet Explorer 6 giving me errors unless it was done that way. I have no idea, it doesn't make sense to me, but who knows?

As for the second argument, yeah that wouldn't be hard at all. Just change return to:

1
return metaword.substr(0,phones);

With some error checking to make sure it's an integer or parseInt it or whatever.

Gravatar
Kevin van Zonneveld
26 Jun '09 Permalink

q  @ Greg Frazier + Brett Zamir: this is really great! one of the missing string functions, good job!

Gravatar
Brett Zamir
26 Jun '09 Permalink

q  @Greg Frazier, Wow, very nice work!

I did a little bit of jslint.com - assisted clean-up, added examples, and fixed one bug (metaword spelled as metword in one place), so please use this version in the future: http://trac.phpjs.org/projects/phpjs/browser/trunk/_workbench/strings/metaphone.js (you can download as text via a link at the bottom of the page)

I haven't looked at the code closely, but are all those uses of the String() object wrapper necessary?

Also, would there be any way to implement the second argument "phones" (for maximum phonemes according to the PHP source)?

When you say there are bugs, can you give test cases/examples? Otherwise, I'd love for us to be able to release this out of the workbench area...

Thanks again, really great to have this one!

Gravatar
Greg Frazier
26 Jun '09 Permalink

q   There are bugs, but in my testing, it's very accurate.

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110111
112
113
114
115116
117
118
119
120121
122
123
124
125126
127
128
129
130131
132
133
134
135136
137
138
139
140141
142
143
144
145146
147
148
149
150151
152
153
154
155156
157
158
159
160161
function metaphone(word){
        var wordlength = word.length;
        var x = 0, tempchar = "";
        var metaword = "";
        var removedbl = function(word){                var wordlength = word.length;
                var tempword = word.toLowerCase();
                var rebuilt;
                var tempchar1, tempchar2;
                var x;                
                tempchar1 = String(tempword).charAt(0);                         
                rebuilt = tempchar1;
                for(x=1;x<wordlength;x++){
                        tempchar2 = String(tempword).charAt(x)                        if(tempchar2 != tempchar1 || tempchar2 == 'c' || tempchar2 == 'g'){
                                rebuilt += tempchar2;
                        }
                        tempchar1 = tempchar2;
                }                return rebuilt;
        }
        var isVowel=function(a){
                switch(a.toLowerCase())
                {                        case 'a': return true; break;
                        case 'e': return true; break;
                        case 'i': return true; break;
                        case 'o': return true; break;
                        case 'u': return true; break;                        default: return false; break;
                }
        };
        var tempword = removedbl(word.toLowerCase());
                //Special wh- case
        if(String(tempword).charAt(0) == 'w' && String(tempword).charAt(1) == 'h'){
                // Remove "h" and rebuild the string
                tempword = "w" + String(tempword).substr(2);
        }        
        for(x=0; x<wordlength; x++){
                tempchar = String(tempword).charAt(x)
                if(x == 0 && x+1 <= wordlength){
                        switch(tempchar){                                case 'a': if(String(tempword).charAt(x+1) == 'e'){ metaword += 'e'; }else{metaword += 'a';} break;
                                case 'e': metaword += 'e'; break;
                                case 'i': metaword += 'i'; break;
                                case 'o': metaword += 'o'; break;
                                case 'u': metaword += 'u'; break;                                                                                       case 'g': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
                                case 'k': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
                                case 'p': if(String(tempword).charAt(x+1) == 'n'){ x += 1; tempchar = String(tempword).charAt(x);} break;
                                case 'w': if(String(tempword).charAt(x+1) == 'r'){ x += 1; tempchar = String(tempword).charAt(x); break;} break;
                        }                }
                if(isVowel(tempchar) == false){
                        switch(tempchar){
                                case 'b': if(String(tempword).charAt(x-1) == 'm'){ break;}else{metaword += 'b';} break;
                                case 'c': if(x+1 <= wordlength){                                                        if(String(tempword).charAt(x+1) == 'h' && String(tempword).charAt(x-1) != 's'){ metaword += 'x'; }else if(String(tempword).charAt(x+1) == 'i' && String(tempword).charAt(x+2) == 'a'){ metaword += 'x';}
                                                        else if(String(tempword).charAt(x+1) == 'i' || String(tempword).charAt(x+1) == 'e' || String(tempword).charAt(x+1) == 'y'){ 
                                                                if(x > 0){
                                                                        if(String(tempword).charAt(x-1) == 's'){
                                                                                break;                                                                        }else{
                                                                                metaword += 's'; 
                                                                        }
                                                                }else{
                                                                        metaword += 's';                                                                 }
                                                        }else{
                                                                metaword += 'k';
                                                        }
                                                  }else{                                                        metaword += 'k';
                                                  }
                                                  break;
                                case 'd': if(x+2 <= wordlength){
                                                        if(String(tempword).charAt(x+1) == 'g'){                                                                 if(String(tempword).charAt(x+2) == 'e' || String(tempword).charAt(x+2) == 'y' || String(tempword).charAt(x+2) == 'i'){ 
                                                                        metaword += 'j';
                                                                        x += 2;
                                                                }else{
                                                                        metaword += 't';                                                                }
                                                        }else{
                                                                metaword += 't';
                                                        }
                                                  }else{                                                                metaword += 't';
                                                  }
                                                  break;
                                case 'f': metaword += 'f'; break;
                                case 'g': if(x < wordlength){                                                        if((String(tempword).charAt(x+1) == 'n' && x+1 == wordlength - 1) || (String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 's' && x+2 == wordlength - 1)){break;}
                                                        if(String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 'e' && String(tempword).charAt(x+3) == 'd' && x+3 == wordlength - 1){break;}
                                                        if(String(tempword).charAt(x-1) == 'n' && String(tempword).charAt(x-2) == 'i' && x == wordlength - 1){break;}
                                                        if(String(tempword).charAt(x+1) == 'h' && x+1 <= wordlength-1 && String(tempword).charAt(x-1) == 'u' && String(tempword).charAt(x-2) == 'o'){metaword += 'f';break;}
                                                        if(String(tempword).charAt(x+1) == 'h' && x+2 <= wordlength){if(isVowel(String(tempword).charAt(x+2)) == false){break; /*silent*/ }else{metaword += 'k';}}                                                        else if(x+1 == wordlength){if(String(tempword).charAt(x+1) == 'n'){break;}else{metaword += 'k';}}
                                                        else if(x+3 == wordlength){if(String(tempword).charAt(x+1) == 'n' && String(tempword).charAt(x+2) == 'e' && String(tempword).charAt(x+3) == 'd'){;}else{metaword += 'k';}}
                                                        else if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'i' || String(tempword).charAt(x+1) == 'e' || String(tempword).charAt(x+1) == 'y'){
                                                                                                        if(String(tempword).charAt(x-1) != 'g'){ metaword += 'j';}
                                                                                                        }else if(x > 0){ if(String(tempword).charAt(x-1) == 'd'){                                                                                                                switch(String(tempword).charAt(x+1)){
                                                                                                                        case 'e':
                                                                                                                        case 'y':
                                                                                                                        case 'i': break;
                                                                                                                        default: metaword += 'k';                                                                                                                                                                                                                                                       }
                                                                                                                }else{metaword += 'k';}
                                                                                                        }else{metaword += 'k';}
                                                        }else{
                                                                metaword += 'k';                                                        }
                                                  }else{
                                                                metaword += 'k';
                                                  }
                                                  break;                                case 'm': metaword += 'm'; break;
                                case 'j': metaword += 'j'; break;
                                case 'n': metaword += 'n'; break;
                                case 'q': metaword += 'k'; break;
                                case 'r': metaword += 'r'; break;                                case 'l': metaword += 'l'; break;
                                case 'v': metaword += 'f'; break;
                                case 'z': metaword += 's'; break;
                                case 'x': if(x == 0){metaword += 's';}else{metaword += 'ks';} break;
                                case 'm': metaword += 'm'; break;                                case 'k': if(x > 0){ if(String(tempword).charAt(x-1) != 'c'){metaword += 'k';}}else{metaword += 'k';} break;
                                case 'p': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){metaword += 'f';}else{metaword +='p';}}else{metaword += 'p';} break;
                                case 'y': if(x+1 <= wordlength){if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'y';}}else{metword += 'y';} break;
                                case 'h': if(x > 0){ if(isVowel(String(tempword).charAt(x-1)) == true){
                                                                                if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'h'; break;}                                                                                break;
                                                                        }
                                                                                switch(String(tempword).charAt(x-1)){
                                                                                        case 'c':
                                                                                        case 's':                                                                                        case 'p':
                                                                                        case 't':
                                                                                        case 'g': break;
                                                                                        default: metaword += 'h';
                                                                                }                                                                        }else{
                                                                                metaword += 'h';
                                                                        }
                                                                        break;
                                case 's': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){ metaword += 'x'; }                                                        else if(x+2 <= wordlength){if(String(tempword).charAt(x+1) == 'i'){if(String(tempword).charAt(x+2) == 'o' || String(tempword).charAt(x+2) == 'a'){metaword += 'x';}else{metaword += 's';}
                                                        }else{metaword += 's';}}else{metaword += 's';}}else{metaword += 's';} break;
                                case 't': if(x+1 <= wordlength){if(String(tempword).charAt(x+1) == 'h'){ metaword += '0'; }
                                                        else if(x+2 <= wordlength){if(String(tempword).charAt(x+1) == 'i'){if(String(tempword).charAt(x+2) == 'o' || String(tempword).charAt(x+2) == 'a'){metaword += 'x';}else{metaword += 't';}
                                                        }else{metaword += 't';}}else{metaword += 't';}}else{metaword += 't';} break;                                case 'w': if(x+1 <= wordlength){if(isVowel(String(tempword).charAt(x+1)) == true){metaword += 'w'}} break;
                        }
                }
        }
        return metaword;}

Gravatar
Brett Zamir
20 Jun '09 Permalink

q  @jhkkhkj: Thanks for the input, but we'd really want it to work like in PHP. Although it's not documented in PHP yet, and it might not be implemented perfectly, I think, based on a quick look at the source, that it should be working now basically as it does in PHP: http://phpjs.org/functions/class_alias

Gravatar
jhkkhkj
20 Jun '09 Permalink

q  

1
2
3
function class_alias() {
    // Your code here
}

Gravatar
Kankrelune
30 May '09 Permalink

q  http://www.webfaktory.info/version_compare.txt

Sorry for multiple post... .. .

@ tchaOo°

Gravatar
Kankrelune
30 May '09 Permalink

q   Why the code is not complete... .. ?

a last test...

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110
function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)        return;
 
    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
    while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
        i1 = i1.toLowerCase();        i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
                break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }            
    }
    if (operator) {
        switch (operator) {
            case '>':            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:                return (compare < 0);
        }
    }
    return compare;
}


if the code is not complete mail me for a complete version... sorry for the flood... .. .

@ tchaOo°

Gravatar
Kankrelune
30 May '09 Permalink

q   Ô_o

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110
function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)        return;
 
    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
        while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
                i1 = i1.toLowerCase();                i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
                        break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }                        
    }
    if (operator) {
        switch (operator) {
            case '>':            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:                return (compare < 0);
        }
    }
    return compare;
}


bye

Gravatar
Kankrelune
30 May '09 Permalink

q   version_compare() conversion... it's a javascript adaptation of the version_compare() php function found on the Pear php_compat package...

> http://pear.php.net/package/PHP_Compat

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
82
83
84
8586
87
88
89
9091
92
93
94
9596
97
98
99
100101
102
103
104
105106
107
108
109
110
function version_compare(version1, version2, operator)
{
    if (!version1)
        return;
    if (!version2)        return;
 
    var v1, v2, compare = 0, i = 0, x = 0;
    var standardise = function(v) {
        v = v.replace(/(^\s*)|(\s*$)/g, "").replace(/[-|_|+]/g,'.').replace(/([^0-9\.]+)/g,'.$1.');        return v.replace(/\.\.*/g,'.').split('.');
    };
    var versions = {
        'dev'   : 0,
        'alpha' : 1,        'a'     : 1,
        'beta'  : 2,
        'b'     : 2,
        'rc'    : 3,
        '#'     : 4,        'p'     : 5,
        'pl'    : 5
    };
    
    v1 = standardise(version1);    v2 = standardise(version2);
    while (!v1[0]) { v1.shift(); }
    while (!v2[0]) { v2.shift(); }
        while (!v1[v1.length-1]) { v1.pop(); }
    while (!v2[v2.length-1]) { v2.pop(); }    x = (v1.length > v2.length) ? v2.length : v1.length;
    
    for (i = 0; i < x; i++) {
        if (v1[i] == v2[i]) 
            continue;        
        i1 = v1[i];
        i2 = v2[i];
        
        if (!isNaN(i1) && !isNaN(i2)) {            compare = (parseInt(i1) < parseInt(i2)) ? -1 : 1;
            break;
        }
        
        if (i1 == '#')            i1 = '';
                else if (!isNaN(i1))
                    i1 = '#';
        
        if (i2 == '#')            i2 = '';
                else if (!isNaN(i2))
                    i2 = '#';
        
                i1 = i1.toLowerCase();                i2 = i2.toLowerCase();
        if (versions[i1] && versions[i2])
           compare = (versions[i1] < versions[i2]) ? -1 : 1;
        else if (versions[i1])
            compare = 1;        else if (versions[i2])
            compare = -1;
        else
            compare = 0;
                        break;
    }
    if (compare == 0) {
        if (v2.length > v1.length) {
            if (versions[v2[i].toLowerCase()])                compare = (versions[v2[i].toLowerCase()] < 4) ? 1 : -1;
                    else
                        compare = -1;
        } 
        else if (v2.length < v1.length) {            if (versions[v1[i].toLowerCase()])
                compare = (versions[v1[i].toLowerCase()] < 4) ? -1 : 1;
                    else
                        compare = 1;
        }                        
    }
    if (operator) {
        switch (operator) {
            case '>':            case 'gt':
                return (compare > 0);
            case '>=':
            case 'ge':
                return (compare >= 0);            case '<=':
            case 'le':
                return (compare <= 0);
            case '==':
            case '=':            case 'eq':
                return (compare == 0);
            case '<>':
            case '!=':
            case 'ne':                return (compare != 0);
            case '':
            case '<':
            case 'lt':
            default:                return (compare < 0);
        }
    }
    return compare;
}


she's work fine...

> http://img20.imageshack.us/my.php?image=testvhw.jpg

Php version credits...

1
2
3
4
56
7
8
9
1011
12
13
14
/**
 * Replace version_compare()
 *
 * @category    PHP
 * @package     PHP_Compat * @license     LGPL - http://www.gnu.org/licenses/lgpl.html
 * @copyright   2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
 * @link        http://php.net/function.version_compare
 * @author      Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @author      Aidan Lister <aidan@php.net> * @version     Revision: 1.16 
 * @since       PHP 4.1.0
 * @require     PHP 4.0.5 (user_error)
 */


cheers

@ tchaOo°

Gravatar
Brett Zamir
2 May '09 Permalink

q  @Theriault, That's awesome to hear. I wasn't looking forward to trying to implement that one. :) I haven't tested your function yet, but wanted to ask if you wouldn't mind testing with http://pastebin.com/m410d37b0 to ensure that we have a somewhat cleaner copy (there was also a debugging alert I commented out, and I changed one use of 'j' to be a new variable 'k' since it seemed like 'k', if on an object, could be a string as we're trying to keep variables to the same type for the sake of declarations/readability (I also wasn't sure about another use of 'j'--line 217 my copy)?, but most of the other changes were for readability, maintainability, and/or early variable "type" declaration--such terse styles may work or save a little space, but can lead to bugs and be more difficult to read/maintain). We're also trying to adhere to http://jslint.com so I'd be most grateful if you could assess whether the remaining gripes of JSLint can be overcome. Also, have you tested with objects? Thank you once again!

Gravatar
Theriault
1 May '09 Permalink

q  I have created working code for the port of array_multisort.

http://pastebin.com/m1d12e821

Gravatar
Khurram Adeeb Noorani
29 Apr '09 Permalink

q   I have better smaller and better solutions for ltrim(), rtrim() and trim()

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
20
function ltrim(str)
{
        while(str.charAt(0)==" ")
                str=str.replace(" ","");
        return str;}
function rtrim(str)
{
        last=str.length-1;
        while(str.charAt(last)==" ")        {
                str=str.substring(0,last);
                last--;
        }
        return str;}
function trim(str)
{
        return ltrim(rtrim(str));
}

Gravatar
Kevin van Zonneveld
19 Apr '09 Permalink

q  @ Brett Zamir: Not really PHP-like, but I don't see how it could conflict either. And I do see how this could be really helpful for JS developers. So yes, I'm cool with that.

Gravatar
Brett Zamir
14 Apr '09 Permalink

q  That looks cool--but could we add one enhancement to allow an array of string options? If one is using the string syntax, it could be convenient to be add flags easily in this way (and see what it is supposed to do without defining constants or passing integers)...

Gravatar
Kevin van Zonneveld
14 Apr '09 Permalink

q  @ Brett Zamir & Francis Lewis: Good job guys, keep it up!
Considering constant / bitwise arguments, I really like the function pathinfo to be an example for how to implement this cause it has full compatibility.

For example, it allows combining multiple arguments just like in PHP.
Checkout the notes of the function for further clarification:
http://phpjs.org/functions/pathinfo:486

Gravatar
Brett Zamir
7 Apr '09 Permalink

q  Oh, as you can see, we've generally implemented constants as the equivalent capitalized strings. However, I think we should support them also as integers (and optionally define all of the constants in the package), especially if bitwise-or'ed to include multiple flags (for strings, we could just allow the user to pass the strings in an array to represent multiple flags for a given argument).

Gravatar
Brett Zamir
7 Apr '09 Permalink

q   I don't have time to work on it now, but here's a skeleton based on your code for implementing all of the aspects of preg_match. Note that the return value should be an integer (for preg_match_all(), the integer can be higher than 0, but not for preg_match).

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
29
3031
32
33
34
3536
37
38
39
4041
42
43
44
4546
47
48
49
5051
52
53
54
5556
57
58
59
6061
62
63
64
6566
67
68
69
7071
72
73
74
7576
77
78
79
8081
function preg_match(pattern, subject, matches, flags, offset) {
    // http://kevin.vanzonneveld.net
    // +   original by: Francis Lewis
    // *     example 1: matches = [];
    // *     example 1: preg_match(/(\w+)\W([\W\w]+)/, 'this is some text', matches);    // *     matches 1: matches[1] == 'this'
 
    var i, array = [], regexpFlags='';
 
    if (typeof pattern === 'string') {        /* // Potentially useful configuration
        if (/a-zA-Z/.test(pattern[0]) || pattern.length === 1) { // The user is probably not using letters for delimiters (not recommended, but could be convenient for non-flagged expressions)
            pattern = new RegExp(pattern);
        }
        else {        */
            var lastDelimPos = pattern.lastIndexOf(pattern[0]);
            if (lastDelimPos === 0) {
                throw 'Improperly formed regular expression passed to '+arguments.callee.name;
            }            var patternPart = pattern.slice(1, lastDelimPos);
            var flagPart = pattern.slice(lastDelimPos+1);
            for (i=0; i < flagPart.length; i++) {
                switch(flagPart[i]) {
                    case 'g': // We don't use this in preg_match, but it's presumably not an error                    case 'm':
                    case 'i':
                        regexpFlags += flagPart[i];
                        break;
                    case 's':                    case 'x':
                    case 'e':
                    case 'A':
                    case 'D':
                    case 'S':                    case 'U':
                    case 'X':
                    case 'J':
                    case 'u':
                        throw 'The passed flag(s) are presently unsupported in '+arguments.callee.name;                        break;
                    case 'y':
                        throw 'Flag "y" is a non-cross-browser, non-PHP flag, not supported in '+arguments.callee.name;
                        break;
                    default:                        throw 'Unrecognized flag passed to '+arguments.callee.name;
                        break;
                }
            }
            patternPart = patternPart.replace(/\(\?<(.*)\)/g, function (namedSubpattern, name) {                return namedSubpattern; // Not implemented
            });
            pattern = new RegExp(patternPart, regexpFlags);
        // }
    } 
    // store the matches in the first indice of the array
    array[0] = pattern.exec(subject);
 
    if (!array[0]) {        return 0;
    }
 
    // If the user passed in a RegExp object or literal, we will probably need to reflect on
    //   its source, ignoreCase, global, and multiline properties to form a new expression, and    //   and use lastIndex
    if (offset) {
        // Not implemented
    }
    if (flags === 'PREG_OFFSET_CAPTURE') {        // Not implemented
        return 1; // matches will need to be different, so we return early here
    }
 
    // loop through the first indice of the array and store the values in the $matches array    for (i = 0; i < array[0].length; i++) {
        matches[i] = array[0][i];
    }
 
    return 1;}

Gravatar
Francis Lewis
6 Apr '09 Permalink

q   It doesn't appear that my previous comment was added here, so trying it again.

Fix - Fixed an issue where array[0] could contain no result if no matches were found and throws an error
Change - Added return true/return false - since this is how the php function works.
Change - Formatted according to the phpjs coding guidelines
Change - Provided a more dynamic example.

Notes: the only items missing at this point are Flags and Offset
The only flag that can be passed in the php version is: PREG_OFFSET_CAPTURE
Please let me know if anybody has an idea how to pass the flag since it's a constant in php... I can only think of passing true/false in that parameter at the moment, but then it wouldn't be true to the php function. Not sure what kind of issues that could bring.

Offset would be a simple use of substr, so substr would be a dependant for this function when that is added

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
19
2021
22
23
24
2526
27
28
function preg_match(regex, input, result) {
    // +   original by: Francis Lewis (http://startrekguide.com)
    // *     example 1: result = [];
    // *     example 1: preg_match(/[\d-]{2}?(\d{3})-(\d{3})-(\d{4})[\W+]?([\W\w]+)?/, '1-800-123-4567 fax', result);
    // *     results 1: result[1] == '800'    // *         results 1: result[2] == '123'
    // *         results 1: result[3] == '4567'
    // *         results 1: result[4] == 'fax'
 
        var i;        var array = {};
        
        // store the result in the first indice of the array
        array[0] = regex.exec(input);
                // make sure the array contains any value
        if (!array[0]) {
                return false;
        }
                // loop through the first indice of the array and store the values in the $result array
        for (i = 0; i < array[0].length; i++) {
                result[i] = array[0][i];
        }
                // we will always have a result at this point, so return true
        return true;
}

Download

Download

There is a wide variety of packages if the default doesn't suit you.
You can also compile your own package to avoid any overhead.

Support us

spread the word:


Use any PHP function in JavaScript


These kind folks have already donated: Anonymous and Shawn Houser.
<your name here>

Click here to lend your support to: phpjs and make a donation at www.pledgie.com !

RSS

Tweets

Comments

Who uses php.js

If you use php.js, let us know and get linked.

Progress

php.js is complete for 83.7%

php.js on

Discuss php.js' future at Google Groups
Help improve php.js on github



Powered by php.js
Stats