Category Archives: string manipulation

TextLineMetrics

Actionscript:
  1. var word:String = "TextLineMetrics are useful";
  2. var letters:Array = word.split("");
  3.  
  4. var pre:TextField;
  5. for (var i:int = 0; i<letters.length; i++){
  6.     var t:TextField = new TextField();
  7.     t.defaultTextFormat = new TextFormat("Arial", 40);
  8.     t.autoSize = TextFieldAutoSize.LEFT;
  9.     t.textColor = int(Math.random() * 0xFFFFFF);
  10.     t.text = letters[i];
  11.     if (pre){
  12.         var metrics:TextLineMetrics = pre.getLineMetrics(0);
  13.         t.x = metrics.width + pre.x;
  14.     }
  15.     pre = t;
  16.     addChild(t);
  17. }

Sometimes you need to do something to a TextField one letter at a time. One way to do this is to create a separate TextField for each letter and position them based on the TextLineMetrics object. This snippet creates textFields for a string and colors each TextField randomly.

Also posted in strings | Tagged , , | 6 Comments

URLVariables Replacement

Actionscript:
  1. function decode(str:String):Object {
  2.     var vars:Object={};
  3.     var parse:Array =str.split("&");
  4.     var i:int=0;
  5.     for (i = 0; i<parse.length; i++) {
  6.         var pair:Array=parse[i].split("=");
  7.         if (pair.length==2) {
  8.             vars[pair[0]]=pair[1];
  9.         }
  10.     }
  11.     return vars;
  12. }
  13.  
  14. var nameValuePairs="one=1&&two=éllo&three=1000&four=0xFF0000";
  15. var parsed:Object=decode(nameValuePairs);
  16.  
  17. trace(parsed.one);
  18. trace(parsed.two);
  19. trace(parsed.three);
  20. trace(parsed.four);
  21.  
  22. /*outputs:
  23. 1
  24. éllo
  25. 1000
  26. 0xFF0000
  27. */

Well not exactly a URLVariables replacement, but I often use the URLVariables.decode() function and find that its very picky... like if there is an extra & or something it freaks out and breaks, or if there are line returns. As a quick and simple solution the other day I wrote this function into part of a class (Model class) that I was working on. Fixed the problem and even handles Spanish characters nicely.

There is plenty of room for improvement with this simple function... feel free to post improvements in the comments.

Also posted in external data, strings | Tagged , , | 3 Comments

ActionScript Eval (well, not really)

Actionscript:
  1. var txt:TextField = TextField(addChild(new TextField()));
  2. txt.autoSize = TextFieldAutoSize.LEFT;
  3.  
  4. var myVar:Number = 100;
  5. // works as an expression parser
  6. txt.text = js("return (" + myVar + " * 2 + 10) / 2");
  7. txt.appendText("\n\n");
  8.  
  9. // parses javascript
  10. txt.appendText(js("var a = []; for (var i = 0; i<10; i++){ a.push(i) } return a;"));
  11.  
  12. function js( data:String ):*{
  13.    var res:*= ExternalInterface.call("function(){" + data + "}");
  14.    return (res == null) ? "null" : res;
  15. }

This one made my day - CAN'T believe I never thought of it before... haven't done any speed tests yet... but it shows how to use ExternalInterface.call to parse math expressions and javascript code. This will only work when the swf is shown in an html page of course... so if your in flash cmd+f12...

I got the idea from this code snippet... which actually has an error in it... the decode() function should not return void... I found that snippet thanks to this tweet by makc3d.

Also posted in Math, external data, functions, misc, strings | Tagged , , | Leave a comment

base32 Twitter Coordinates

Actionscript:
  1. [SWF(width = 800, height=700, frameRate=30, backgroundColor=0x000000)]
  2. var canvas:BitmapData = new BitmapData(1000,800,false, 0x000000);
  3. addChild(new Bitmap(canvas));
  4.  
  5. var coords:String ="";
  6. var index:int = 0;
  7. addEventListener(Event.ENTER_FRAME, onLoop);
  8.  
  9. var s:Shape = new Shape();
  10. with (s.graphics) beginFill(0xFFFFFF, 0.3), drawCircle(4,4,4)
  11. var brush:BitmapData = new BitmapData(10,10, true, 0x00000000);
  12. brush.draw(s);
  13.  
  14. var pnt:Point = new Point();
  15. function onLoop(evt:Event):void {
  16.      if (coords.length> 0){
  17.          for (var i:int = 0; i<100;i++){
  18.              if (index <coords.length){
  19.                  pnt.x+= 0.2;
  20.                  pnt.y = parseInt(coords.substr(index,3), 32) / 2;
  21.                  index+=3;
  22.                  canvas.copyPixels(brush, brush.rect, pnt, null, null, true);
  23.              }else{
  24.                 break;
  25.                 removeEventListener(Event.ENTER_FRAME, onLoop);
  26.              }
  27.          }
  28.      }
  29. }
  30.  
  31. var loader:URLLoader = new URLLoader();
  32. var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
  33. var vars:URLVariables = new URLVariables();
  34. vars.q = "as3, flash";
  35. vars.rpp = "100";
  36. vars.page = 1;
  37. vars.lang = "en";
  38. req.data = vars;
  39. req.method = URLRequestMethod.POST;
  40. loader.load(req);
  41. loader.addEventListener(Event.COMPLETE, onLoaded);
  42. function onLoaded(evt:Event):void{
  43.     var searchData:XML = new XML(loader.data);
  44.     var atom:Namespace = searchData.namespace("");
  45.     default xml namespace = atom;
  46.     var titles:String = "";
  47.     for each(var entry:XML in searchData.entry){
  48.         titles += entry.title.toString();
  49.     }
  50.     var index:int = 0;
  51.     var words:Array = titles.split(" ");
  52.     words.sort();
  53.     for (var i:int = 0; i<words.length; i++){
  54.         if (words[i].match(/RT|\@|\#|http/g).length == 0){
  55.             var word:String = words[i].replace(/[\W]/g, "");
  56.             if (word.length> 1){
  57.                 coords += word + " ";
  58.             }
  59.         }
  60.     }
  61. }

This snippet does a twitter search and sorts the results alphabetically. It then reads through the results 3 characters at a time - each set of 3 characters is converted to base32 and then used a y coordinate on a plot.

In order for the swf to be worth looking at, I think I'd need to add an input field. I may do that later... but for now here are a few stills:

Also posted in BitmapData, external data, strings | Tagged , , , | 2 Comments

Twitter Texture Alphabet

Actionscript:
  1. [SWF(width = 1000, height=800, frameRate=60)]
  2.  
  3. // if you don't have flex you'll need to embed this font in your library
  4. [Embed(source="/Library/Fonts/Verdana.ttf", fontFamily="Verdana")]
  5. var Verdana:Class;
  6.  
  7. var canvas:BitmapData = new BitmapData(1000,800,false, 0xFFFFFF);
  8. addChild(new Bitmap(canvas));
  9. var overlay:BitmapData = new BitmapData(1000,800,true, 0x01FFFFFF);
  10.  
  11.  
  12. var txt:TextField = TextField(addChild(new TextField()));
  13. with (txt){
  14.     defaultTextFormat = new TextFormat("Verdana", 10);
  15.     embedFonts = true;
  16.     width = stage.stageWidth-20;
  17.     height = stage.stageHeight-20;
  18.     multiline = true;
  19.     wordWrap = true;
  20.     text ="";
  21.     textColor = 0x444444;
  22.     selectable = false;
  23.     x = y = 10;
  24.     text = "loading...";
  25. }
  26.  
  27.  
  28. var selectWords:Array = [];
  29. var currFirstLetter:String="";
  30. var prevFirstLetter:String="";
  31. var index:int = 0;
  32. var anchorX:Number = 0, anchorY:Number = 0, theta:Number, radius:Number;
  33. addEventListener(Event.ENTER_FRAME, onLoop);
  34. function onLoop(evt:Event):void {
  35.      canvas.copyPixels(overlay, overlay.rect, new Point(0,0), null, null, true);
  36.      var leng:int = selectWords.length;
  37.      if (leng> 0){
  38.          var word:String = selectWords[index % leng];
  39.          trace(word);
  40.          currFirstLetter = word.charAt(0);
  41.          if (currFirstLetter != prevFirstLetter){
  42.              anchorX = Math.random() * (stage.stageWidth - 200) + 100
  43.              anchorY = Math.random() * (stage.stageHeight - 200) + 100;
  44.              theta = Math.random() * Math.PI * 2;
  45.              radius = 50 + Math.random() * 100;
  46.              txt.textColor = [0,0xFFFFFF,0xCCCCCC,0x666666][int(Math.random()*4)];
  47.          }else{
  48.              txt.x = anchorX + radius * Math.cos(theta);
  49.              txt.y = anchorY + radius * Math.sin(theta);
  50.              theta += Math.random() * .1;
  51.              radius += 3;
  52.              txt.scaleX = txt.scaleY = 1 + Math.random();
  53.              if (int(Math.random()*30) == 1) txt.scaleX = txt.scaleY = 1 + Math.random()*10;
  54.              txt.rotation = theta / Math.PI * 180;
  55.              txt.text = word;
  56.              canvas.draw(txt, txt.transform.matrix);
  57.          }
  58.          prevFirstLetter = currFirstLetter;
  59.          index++;
  60.      }
  61. }
  62.  
  63. var loader:URLLoader = new URLLoader();
  64. var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
  65. var vars:URLVariables = new URLVariables();
  66. vars.q = "alphabet";
  67. // results per page
  68. vars.rpp = "100";
  69. vars.page = 1;
  70. vars.lang = "en";
  71.  
  72. req.data = vars;
  73. req.method = URLRequestMethod.POST;
  74. loader.load(req);
  75. loader.addEventListener(Event.COMPLETE, onLoaded);                                 
  76. function onLoaded(evt:Event):void{
  77.     var searchData:XML = new XML(loader.data);
  78.     var atom:Namespace = searchData.namespace("");
  79.     default xml namespace = atom;
  80.     var titles:String = "";
  81.     for each(var entry:XML in searchData.entry){
  82.         titles += entry.title.toString();
  83.     }
  84.     var index:int = 0;
  85.     var words:Array = titles.split(" ");
  86.     for (var i:int = 0; i<words.length; i++){
  87.         // exclude a few things
  88.         if (words[i].match(/RT|\@|\#|http/g).length == 0){
  89.             selectWords[index++] = words[i].replace(/\s|\r|\n|\"/g, "");
  90.         }
  91.     }
  92.     selectWords.sort();
  93.     txt.text =""
  94.        removeChild(txt);
  95. }

This snippet draws a texture using a twitter search for the word "alphabet". The results are arranged alphabetically and used to draw a texture.


Have a look at the swf:

Also posted in BitmapData, external data, strings | Tagged , , , | 2 Comments

I want Twitter

Actionscript:
  1. [SWF(width = 800, height=600, frameRate=15)]
  2.  
  3. var littleTxt:TextField = TextField(addChild(new TextField()));
  4. with (littleTxt){
  5.     defaultTextFormat = new TextFormat("_sans", 10);
  6.     width = stage.stageWidth-20;
  7.     height = stage.stageHeight-20;
  8.     multiline = true;
  9.     wordWrap = true;
  10.     text ="";
  11.     textColor = 0x444444;
  12.     selectable = false;
  13.     x = y = 10;
  14. }
  15.  
  16. var txt:TextField = TextField(addChild(new TextField()));
  17. with (txt){
  18.     defaultTextFormat = new TextFormat("_sans", 90);
  19.     autoSize = "center";
  20.     x = 0
  21.     y = stage.stageHeight / 2 - 61
  22.     width = stage.stageWidth;
  23.     selectable = false;
  24.     text = "loading";
  25. }
  26.  
  27. var selectWords:Array = [];
  28. addEventListener(Event.ENTER_FRAME, onLoop);
  29. function onLoop(evt:Event):void {
  30.      if (selectWords.length> 0){
  31.         var word:String = selectWords[int(Math.random() * selectWords.length)];
  32.         txt.text = word;
  33.         littleTxt.appendText(word+" ");
  34.      }
  35. }
  36.  
  37. var loader:URLLoader = new URLLoader();
  38. var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
  39. var vars:URLVariables = new URLVariables();
  40. vars.q = "i want";
  41. // results per page
  42. vars.rpp = "50";
  43. vars.page = 1;
  44. vars.lang = "en";
  45.  
  46. req.data = vars;
  47. req.method = URLRequestMethod.POST;
  48. loader.load(req);
  49. loader.addEventListener(Event.COMPLETE, onLoaded);                                 
  50. function onLoaded(evt:Event):void{
  51.     var searchData:XML = new XML(loader.data);
  52.     var atom:Namespace = searchData.namespace("");
  53.     default xml namespace = atom;
  54.     var titles:String = "";
  55.     for each(var entry:XML in searchData.entry){
  56.         titles += entry.title.toString();
  57.     }
  58.     var index:int = 0;
  59.     var words:Array = titles.split(" ");
  60.     for (var i:int = 0; i<words.length; i++){
  61.         // exclude a few things
  62.         if (words[i].match(/RT|\@|\#|http/g).length == 0){
  63.             selectWords[index++] = words[i];
  64.         }
  65.     }
  66. }

This snippet searches twitter for the phrase "I want" and then displays the results randomly word by word in a somewhat hypnotic way.


Have a look at the swf...

Also posted in external data, strings | Tagged , , , | 5 Comments

Dot Syntax from String

Actionscript:
  1. function dotSyntax(target:*, path:String):* {
  2.     var level:Array=path.split(".");
  3.     var curr:* = target;
  4.     for (var i:int = 0; i<level.length; i++) {
  5.         curr=curr[level[i]];
  6.     }
  7.     return curr;
  8. }
  9.  
  10. trace(dotSyntax(this, "stage.stageWidth"));
  11. trace(dotSyntax(this, "graphics"));
  12. trace(dotSyntax(this, "root.loaderInfo.bytesTotal"));
  13.  
  14. /*outputs something like:
  15. 800
  16. [object Graphics]
  17. 1230
  18. */

This snippet shows how to parse dot syntax from a string. It does this by splitting the string and then using square bracket syntax. This is one of the main techniques that makes yesterdays post possible.

Also posted in dynamic, strings | Tagged , , | Leave a comment

XML to ActionScript #3 (AsXML)

XML:
  1. <code>
  2.   <make reference="w" class="BasicView" args="stage.stageWidth, stage.stageHeight, false"/>
  3.   <call method="addChild" args="w"/>
  4.  
  5.   <make reference="wireMat" class="WireframeMaterial" args="0x000000" />
  6.  
  7.   <make reference="sphere" class="Sphere" args="wireMat, 100" />
  8.  
  9.   <call method="w.scene.addChild" args="sphere" />
  10.  
  11.   <make reference="animation" class="Object">
  12.     <set z="-500" rotationY="360"  rotationX="360" ease="Back.easeOut"/>
  13.   </make>
  14.  
  15.   <call method="TweenLite.to" args="sphere, 3, animation" />
  16.  
  17.   <call method="setInterval" args="w.singleRender, 32" />
  18.  
  19. </code>

This snippet shows XML that the mini-library AsXML can read and run - in this case AsXML is set up to run with Papervision

A few days ago I had the idea to write some code that would run ActionScript based on XML. I spent some time getting rid of a few bugs and setting up some demos with TweenLite, Papervision and QuickBox2D. I wrapped everything up into a mini-library called AsXML.

Check out the demos here.


Download AsXML and demo files here.

AsXML Features:
1) call methods of the main timeline
2) read and write properties on the main timeline
3) instantiate classes on the main timeline
4) call methods on these classes
5) read and write properties on these classes
6) store references to return values from functions

Also posted in Box2D, Graphics, Math, QuickBox2D, XML, dynamic, external data, instantiation, misc, motion, return values, strings | Tagged , , | 11 Comments

XML to ActionScript

Actionscript:
  1. // this xml is inline but could easily be in an external file
  2. var script:XML=<code>
  3.  
  4.   <!-- // call some methods of the main timeline graphics property -->
  5.   <call method="graphics.beginFill" args="0xFF0000" />
  6.    
  7.   <call method="graphics.drawRect" args="0, 0">
  8.      <!-- // use this to access properties of the main movie -->
  9.      <!-- // and use them as arguments -->
  10.      <arg reference="stage.stageWidth" />
  11.      <arg reference="stage.stageHeight" />
  12.   </call>
  13.  
  14.   <call method="graphics.endFill" args=""/>
  15.  
  16.   <call method="graphics.beginFill" args="0x0000FF">
  17.      <!-- //regular non-reference arguments can be passed like this -->
  18.      <arg value="0.5" />
  19.   </call>
  20.  
  21.   <call method="graphics.drawCircle" args="100,100,20" />
  22.  
  23.   <call method="customFunction" args="hello">
  24.      <arg reference="root.loaderInfo.bytesTotal" />
  25.   </call>
  26.  
  27. </code>
  28.  
  29. function customFunction(a:String, b:String):void{
  30.     trace("I am a custom function called from xml");
  31.     trace("Here is an argument: " + a);
  32.     trace("Here is another argument, (total bytes of this swf): " + b);
  33. }
  34.  
  35. // parse and run
  36. runCode(script);
  37.  
  38. function runCode(code:XML):void{
  39.     var children:XMLList = code.children();
  40.     for (var i:int = 0; i<children.length(); i++){
  41.         var child:XML = children[i];
  42.         var type:String = child.name();
  43.         if (type == "call"){
  44.             runMethod(child);
  45.         }
  46.     }
  47. }
  48.  
  49. function runMethod(code:XML):void{
  50.     var i:int = 0;
  51.     // get a reference to the function
  52.     var method:Function = dotSyntax(code.@method);
  53.     // call the function if there are no arguments
  54.     if (code.@args.toXMLString().length == 0 && code.arg.length() == 0){
  55.         method();
  56.     }else{
  57.      
  58.      var args:Array = code.@args.split(",");
  59.      var childArgsLength:int = code.arg.length()
  60.      for (i = 0; i<childArgsLength; i++){
  61.           // add another one with dot syntax
  62.           var val:String = code.arg[i].@value;
  63.           if (val){
  64.             args.push(val);
  65.           }
  66.       }
  67.       for (i = 0; i<args.length; i++){
  68.           if (args[i] != ""){
  69.             args[i] = valueType(args[i]);
  70.           }
  71.       }
  72.       for (i = 0; i<code.arg.length(); i++){
  73.          var rs:String = code.arg[i].@reference;
  74.          if (rs){
  75.              var ref:* = dotSyntax(rs);
  76.              args.push(ref);  
  77.          }
  78.       }
  79.       // run the function
  80.       method.apply(null,args);
  81.     }
  82. }
  83.  
  84. // parse dot syntax and return the last property or method
  85. function dotSyntax(str:String):*{
  86.     var path:Array = str.split(".");
  87.     var curr:* = this;
  88.     for (var i:int = 0; i<path.length; i++){
  89.         curr = curr[path[i]]
  90.     }
  91.     return curr;
  92. }
  93.  
  94. function valueType(val:*):* {
  95.     if (isNaN(Number(val))) {
  96.            // remove leading and trailing white
  97.            // remove "" around strings
  98.            val = val.replace(/^s+|s+$/g,"").replace(/^"|"$/g,"");
  99.            //  see if it's a boolean
  100.            if (val == "true"){
  101.                val = true;
  102.            }else if (val == "false"){
  103.                val = false
  104.            }
  105.     } else {
  106.         val = Number(val);
  107.     }
  108.     return val;
  109. }

WARNING: There area few small bugs in this snippet. If you'd like to use this, check out the AsXML mini-library

A few days ago I had the idea to write some code that would parse ActionScript from XML. The features that I realized would be possible are:

1) call methods of the main timeline
2) read and write properties on the main timeline
3) instantiate classes on the main timeline
4) call methods on these classes
5) read and write properties on these classes

So this morning I wrote the first part. This snippet has the ability to read an XML file and call methods accordingly. It also has the ability to read properties of the main timeline and pass them to these methods.

The XML in this snippet draws a box using the stageWidth and stageHeight. It draws a transparent circle and then calls a custom function. The custom function gets passed the root.loaderInfo.bytesTotal property.

I've done something similar a few times where I specifically targeted the Graphics API. This takes that to the next level by potentially working with any ActionScript classes (excluding Vector maybe... need to think about that).

I'll post another version with more features tomorrow. At the very least it will have class instantiation.

Also posted in XML, dynamic, external data | Tagged , , | 6 Comments

Random Guitar Tablature

Actionscript:
  1. // number of notes in chord
  2. var noteNum:int = 3;
  3. var lowNote:Number = 0;
  4. var highNote:Number = 4;
  5. // delay between chords
  6. var delay:int = 2000;
  7. ////////////////////////////////////////
  8. var chord:String = "";
  9. highNote += 1;
  10. var tab:TextField = TextField(addChild(new TextField()));
  11. tab.x = tab.y = 20;
  12. tab.defaultTextFormat = new TextFormat("Courier", 12);
  13. tab.multiline = true;
  14. tab.width = 200;
  15.  
  16. changeChord();
  17. setInterval(changeChord, delay);
  18.  
  19. function changeChord():void{
  20.     var strings:Array = [];
  21.     strings[0] = "e|---------------\n"
  22.     strings[1] = "B|---------------\n"
  23.     strings[2] = "G|---------------\n"
  24.     strings[3] = "D|---------------\n"
  25.     strings[4] = "A|---------------\n"
  26.     strings[5] = "E|---------------\n"
  27.    
  28.     for (var i:int = 0; i<3; i++){
  29.         var place:int = 5 + i * 4;
  30.         var choices:Array = [0,1,2,3,4,5];
  31.         for (var j:int = 0; j<noteNum; j++){
  32.             var ii:int = int(Math.random()*choices.length);
  33.             var index:int = choices[ii];
  34.             strings[index] = strings[index].slice(0, place) + (int(Math.random()*highNote)+lowNote) +  strings[index].substring(place+1);
  35.             choices.splice(ii, 1);
  36.         }
  37.     }
  38.     chord = strings.join("");
  39.     tab.text = chord;
  40. }

I'm working on a small program to help me practice guitar. It randomly generates guitar tabs. The idea for the program is similar to a program that helps you learn to type (like Mavis Beacon).

I wrote this snippet today as a proof of concept - just to help me start thinking about what kind of features I want the program to have. There are settings at the top so that you can tweak the number of notes in the chord and the delay between chords etc....

It generates three chords at a time... here are some stills:

Also posted in random, strings | Tagged , , | 6 Comments