World: r4wp
[Rebol School] REBOL School
older newer | first last |
GrahamC 24-Apr-2012 [104] | I guess i should just make a rule for each type of call and then combine them. |
Gregg 24-Apr-2012 [105x4] | Here's something for US phone numbers I did a long time ago |
set 'parse-phone-num func [ num [string!] /local digit digits sep _ext_ ch nums pin ext ] [ digit: charset "0123456798" digits: [some digit] sep: charset "()-._" _ext_: ["ext" opt "." | "x"] nums: copy "" rules: [ any [ some [sep | copy ch digit (append nums ch)] | _ext_ copy ext digits | "pin" copy pin digits ] end ] either parse trim num rules [reduce ['num nums 'ext ext 'pin pin]] [none] ] set 'well-formed-phone-number? func [num /local data] [ either none? data: parse-phone-num num [false] [ any [ found? find [7 10] length? data/num all [11 = length? data/num data/num/1 = #"1"] ] ] ] | |
And a formatter that goes the other way: | |
set 'format-phone-number func [ num [string! object!] "String or object with /text value" /def-area-code area-code [string! integer!] /local left right mid obj res ] [ left: func [s len][copy/part s len] right: func [s len] [copy skip tail s negate len] mid: func [s start len][copy/part at s start len] if object? num [obj: num num: obj/text] res: either data: parse-phone-num num [ ; discard leader if it's there. if all [11 = length? data/num data/num/1 = #"1"] [ data/num: right data/num 10 ] rejoin [ rejoin switch/default length? data/num [ 7 [ compose [ (either area-code [rejoin ["(" area-code ") "]][]) left data/num 3 "-" right data/num 4 ]] 10 [[ "(" left data/num 3 ") " mid data/num 4 3 "-" right data/num 4 ]] ][[data/num]] reduce either data/ext [[" ext" trim data/ext]] [""] reduce either data/pin [[" pin" trim data/pin]] [""] ] ][num] if obj [ obj/text: res attempt [if 'face = obj/type [show obj]] ] res ] | |
GrahamC 24-Apr-2012 [109x2] | Ok, so this checks for legally formatted numbers. Or formats numbers into the common format. |
need to reboot .. clipboard not working. When is openme coming :( | |
Gregg 24-Apr-2012 [111] | Yes. :-) |
GrahamC 24-Apr-2012 [112x3] | p: format-phone-number "1800-123456" == "(180) 012-3456" |
might need a ittle tweaking for international numbers | |
How are international numbers formatted? +181812345678 ? | |
Gregg 24-Apr-2012 [115x2] | As I said, it was just for US phone numbers. The +1 was not included, since it wasn't meant for dialing. |
If you're asking how they're formatted in general, it depends. | |
GrahamC 24-Apr-2012 [117] | ok, so always 3 numbers in the first group if not international? |
Gregg 24-Apr-2012 [118] | Yes. |
GrahamC 24-Apr-2012 [119x2] | ( we use 2 numbers for the first group unless it's cellular when it's 3 or 4 ) |
can a number start with 1 ? | |
Gregg 24-Apr-2012 [121] | IIRC, some places use 4, grouping them into 2 sets of 2 for the area code. |
GrahamC 24-Apr-2012 [122x2] | ohh .... |
I guess users are going to have to make their own parse rules then | |
Gregg 24-Apr-2012 [124x2] | The code I posted doesn't do any validation according to what might work in the real world when dialed. |
http://msdn.microsoft.com/en-us/goglobal/bb688129 http://en.wikipedia.org/wiki/Telephone_numbering_plan I think the number of options are limited enough that you could get pretty far, but a custom system would be great. If you could template-ize things, users could submit their templates for others to use, or to be integrated into the default system. | |
GrahamC 24-Apr-2012 [126] | These rules are going into a cgi script to allow local and national dialiing (and emergency) but stop international |
Gregg 24-Apr-2012 [127] | Ah, there you go. Validate against your local and national rules and fail everything else. |
GrahamC 24-Apr-2012 [128] | yep |
Gregg 24-Apr-2012 [129x4] | Not sure if this will help, but maybe: |
parse-int-values: func [ "Parses and returns integer values, each <n> chars long in a string." input [any-string!] spec [block!] "Dialected block of commands: <n>, skip <n>, done, char, or string" /local gen'd-rules ; generated rules result ; what we return to the caller emit emit-data-rule emit-skip-rule emit-literal-rule emit-data digit= n= literal= int-rule= skip-rule= literal-rule= done= build-rule= data-rule skip-rule ][ ; This is where we put the rules we build; our gernated parse rules. gen'd-rules: copy [] ; This is where we put the integer results result: copy [] ; helper functions emit: func [rule n] [append gen'd-rules replace copy rule 'n n] emit-data-rule: func [n] [emit data-rule n] emit-skip-rule: func [n] [emit skip-rule n] emit-literal-rule: func [value] [append gen'd-rules value] emit-data: does [append result to integer! =chars] ; Rule templates; used to generate rules ;data-rule: [copy =chars n digit= (append result to integer! =chars)] data-rule: [copy =chars n digit= (emit-data)] skip-rule: [n skip] ; helper parse rules digit=: charset [#"0" - #"9"] n=: [set n integer!] literal=: [set lit-val [char! | any-string!]] ; Rule generation helper parse rules int-rule=: [n= (emit-data-rule n)] skip-rule=: ['skip n= (emit-skip-rule n)] literal-rule=: [literal= (emit-literal-rule lit-val)] done=: ['done (append gen'd-rules [to end])] ; This generates the parse rules used against the input build-rule=: [some [skip-rule= | int-rule= | literal-rule=] opt done=] ; We parse the spec they give us, and use that to generate the ; parse rules used against the actual input. If the spec parse ; fails, we return none (maybe we should throw an error though); ; if the data parse fails, we return false; otherwise they get ; back a block of integers. Have to decide what to do if they ; give us negative numbers as well. either parse spec build-rule= [ either parse input gen'd-rules [result] [false] ] [none] ] | |
Example: parse-int-values "1234567890" [2 4 skip 2 2] | |
parse-int-values "(123) 456-7890" [#"(" 3 ") " 3 #"-" 4] | |
GrahamC 24-Apr-2012 [133] | http://en.wikipedia.org/wiki/Telephone_numbers_in_New_Zealand learnt something new .. 02 is for Scott Base in Antarctica ;) |
Gregg 24-Apr-2012 [134x2] | We had a REBOLer who worked there some years back. ...what was his name... |
G. Scott Jones? Now it's gonna bother me. :-\ | |
GrahamC 24-Apr-2012 [136] | yeah... though he won't be in Scott Base but the USA base there |
Gregg 24-Apr-2012 [137] | Still probably a local call from Scott Base though. ;-) |
GrahamC 24-Apr-2012 [138x3] | maybe not .. it may be routed thru the USA :) |
zero: charset [ #"0" ] digit: charset [ #"0" - #"9" ] digits: [ some digit ] local-number: charset [ #"3" #"4" #"6" #"9" ] not01-number: charset [ #"2" - #"9" ] national-rule: [ zero local-number not01-number digits] local-rule: [ not01-number digits ] emergency-rule: [ "111" ] ; toll free numbers are 0800 and 0508 toll-free: [ zero [ "800" | "508" ] digits ] ; directory assistance 018, 0172, directory-assistance: [ "01" [ "8" | "72" ]] ; faults 120, 125 and business 126 faults: [ "12" [ "0" | "5" | "6" ]] ; cellular are 021, 022, 027, 028, 029 cellular-rule: [ "02" digits ] ; international 00 - country code - number international-rule: [[ "00" | "+" ] digits ] allowed-phone-rule: [ local-rule | national-rule | emergency-rule | toll-free | directory-assistance | faults | cellular-rule ] all-phone-rule: [ allowed-phone-rule | international-rule ] | |
hope that covers all of my dialling rules | |
Endo 25-Apr-2012 [141] | Also check E164 formatting: http://en.wikipedia.org/wiki/E.164 and http://www.wtng.info/wtng-tt.html |
Arnold 26-Apr-2012 [142x2] | In PHP I had a Unix timestamp, which I didn't like, but it is in my database, so now I need this in my REBOL script too. |
Oh found a solution at http://www.rebol.net/cookbook/recipes/0051.html which works | |
Endo 26-Apr-2012 [144x2] | I use this function: Int2Date: func [i][1-Jan-1970/0:00 + to-time i] i is unix style date (seconds from 1970) you may need to change 0:00 to your GMT, if you don't store GMT separately. |
And for the oposite: Date2Int: func [d /local c][ c: 1-Jan-1970/0:00 d - c * 86400 + to-integer d/time - c/time ] | |
james_nak 26-Apr-2012 [146] | Christopher Gill's form-date.r is something I can't live without. http://www.rebol.org/view-script.r?script=form-date.r |
Endo 26-Apr-2012 [147] | I use my own functions, returns always in ISO format, YYYY-MM-DD HH:NN:SS padz: func ["Pad to right with zero." s n [integer!] /left /with c [char! string!]] [ head insert/dup either left [tail form s] [form s] first form either with [c] [#"0"] n - length? form s ] format-date: func [d [date!]] [ ajoin [d/date/year "-" padz d/date/month 2 "-" padz d/date/day 2 either d/time [ajoin [" " padz d/time/hour 2 ":" padz d/time/minute 2 ":" padz to-integer d/time/second 2]] [""]] ] |
Gabriele 27-Apr-2012 [148] | endo, Date2Int can be simplified as: >> to integer! difference now 1-jan-1970/0:00 == 1335506831 |
Endo 27-Apr-2012 [149] | That is much better. Thank you Gabriele! |
Gregg 27-Apr-2012 [150x4] | DIFFERENCE will fail for future dates, starting mid-January 2038. ;>> difference 19-jan-2038/3:14:07 1-Jan-1970/0:0:0 ;== 596523:14:07 ;>> difference 19-jan-2038/3:14:08 1-Jan-1970/0:0:0 ;== --596523:-14:-08 ;>> difference 19-jan-2038/3:14:09 1-Jan-1970/0:0:0 ;== -596523:14:07 |
Here's an old func I use: | |
date-to-epoch: func [ "Returns a unix time (epoch) format from a date." date [date!] ][ ; If no time is given, negate our zone to give us 0:00 UTC if none? date/time [date/time: negate now/zone] ; This uses the epoch base in UTC, so we assume that either ; the date is also in UTC, or has a zone offset included. ; DIFFERENCE fails for huge time differences, so we subtract ; them instead, giving us a difference in days, and multiply ; by the number of seconds in a day. either attempt [positive? res: to integer! difference date 1-Jan-1970/0:0:0] [res] [date - 1-Jan-1970/0:0:0 * 86400.0] ] | |
I believe the reason I still have DIFFRENCE in there, as far as it will work, is for greater accuracy. I don't remember why I have the zone negation bit in there, but I probably hit some issue that required it. | |
older newer | first last |