Hacker News new | ask | show | jobs
by lumberjack 2039 days ago
I use wolframalpha and convert everything to millilitres and grams as appropriate. Most times you don't even need to distinguish between volume and weight because wolframalpha also does that conversion for you.
1 comments

To not have to go to DDG or WA manually, I wrote a script to convert stupid measurements on a page, but I can't say it turned out very well.

In case someone wants to try it out or improve it, open a recipe website and run the code. Or uncomment the console.log() line at the bottom, comment out the document.x line, and run it from the command line (`js code.js`).

    // todo:
    //    - °F matches hex codes ("abcd64fabcd")
    //    - fluid ounce?
    //    - "([0-9]{2,5}) degrees" especially when N > 300
    
    var test = 'Take 1/4-1/2 cup of water, 3 1/2 c. marinara sauce, two ounces of potatoes and three to five tbsp gold.\nOr perhaps 1/8 oz. of gold.\nBake at 350F or with degrees symbol 350°F!';
    test = 'one 29 oz can black beans, rinsed and drained\none 6 oz can tomato paste\n32 oz vegetable stock\n1 onion, chopped\n5 cloves garlic, minced\n1 tablespoon chili powder\n1 tablespoon cumin\n1 teaspoon oregano\n1 tablespoon olive oil\n1 sweet potato, peeled and cut into bite sized chunks\n1 cup dry quinoa\nsalt and pepper to taste\navocado, cilantro for garnish  (optional)\n\nHeat the oil in a large heavy soup pot over medium low heat. Add onions, and cook until soft and they start to turn brown (about 10 minutes). Add the garlic, and cook for about 2 minutes.\nAdd the tomato paste, chili powder, cumin, and oregano and cook for about 2 minutes, stirring constantly.\nAdd the beans, stock, and potatoes, and season with salt and pepper.\nCook for about 5 minutes, then add the quinoa. Continue cooking for about 15 minutes – 30 minutes, stirring frequently, until quinoa and potatoes are cooked and the chili has thickened.\nAdd a bit of water if the chili becomes too thick for your liking. Top with avocado and chopped cilantro. Scrumptious!';
    test = 'Chocolate is very sensitive to high temperatures and different chocolates require different maximum temperatures. Dark chocolate should never be heated above 120 F, while milk and white chocolates should never be heated to above 110 F. It is quite easy to exceed these temperatures if using a double boiler with boiling water, or if microwaving on full power'
    test = 'one 29 oz can black beans, rinsed and drained\none 6 oz can tomato paste\n32 oz vegetable stock\n1 onion, chopped\n5 cloves garlic, minced\n1 tablespoon chili powder\n1 tablespoon cumin\n1 teaspoon oregano\n1 tablespoon olive oil\n1 sweet potato, peeled and cut into bite sized chunks\n1 cup dry quinoa\nsalt and pepper to taste\navocado, cilantro for garnish  (optional)'
    
    function fixSizes(str, debug) {
     var SIprefix = function(amount) {
      if (amount > 1000) {
       return (Math.round(amount / 1000 * 10) / 10).toString() + 'k';
      }
      if (amount < 1) {
       return (Math.round(amount * 1000 * 10) / 10).toString() + 'm';
      }
      return amount.toString();
     };
    
     var volume = function(amount, ratio) {
      return SIprefix(amount * ratio) + 'l';
     };
     var weight = function(amount, ratio) {
      return SIprefix(amount * ratio) + 'g';
     };
     var fahrenheit = function(amount) {
      return (Math.round((amount - 32) * (5 / 9) * 10) / 10).toString() + '°C';
     };
    
     // units = [ [from, type, rate], ... ]
     // from = list of names, e.g. ['ounce','oz.']. The 's' suffix is automatically checked for, so you don't need to specify 'ounces'.
     // type is one of weight, volume, fahrenheit.
     // rate is: if weight, the ratio of $from to grams; if volume, the ratio of $from to litres; if fahrenheit, omitted.
     var units = [
      [['°F', 'F'], fahrenheit],
      [['cup', 'c.'], volume, 0.25],
      //[['tsp.', 'teaspoon'], volume, 0.0049],
      //[['tbsp', 'tbs', 'tblsp', 'tablespoon'], volume, 0.0148],
      [['lb'], weight, 453.6],
      [['ounce', 'oz.', 'oz'], weight, 28.4],
     ];
    
     var strtonumber = function(s) {
      switch (s) {
       case 'a': case 'an': case 'one': return 1;
       case 'two': return 2;
       case 'three': return 3;
       case 'four': return 4;
       case 'five': return 5;
       case 'six': return 6;
       case 'seven': return 7;
       case 'eight': return 8;
       case 'nine': return 9;
       case 'ten': return 10;
       case 'eleven': return 11;
       case 'twelve': return 12;
       case '1/2': return 1/2;
       case '1/4': return 1/4;
       case '1/8': return 1/8;
      }
      return amount = parseInt(s); // TODO float values. But the regex atm doesn't match that. Didn't encounter any decimals in recipes yet.
     };
    
     var re_unit = '';
     for (var unit in units) {
      for (var alias in units[unit][0]) {
       re_unit += '|' + units[unit][0][alias].replace('.', '\\.');
      }
     }
     re_unit = '(' + re_unit.substring(1) + ')';
    
     var re_number = 'a|an|1/2|1/4|1/8|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|[1-9][0-9]*';
     var re_numeric = '^[1-9][0-9]*$';
     var re_amount = '(((' + re_number + ') to )?(' + re_number + ')|(' + re_number + ')( |-)(' + re_number + '))';
    
     var re_full = new RegExp(re_amount + '( )?' + re_unit + '(s?)', 'igm');
     var re_numeric = new RegExp(re_numeric);
     re_number = new RegExp(re_number, 'igm');
     re_amount = new RegExp(re_amount, 'igm');
     re_unit_noplural = new RegExp(re_unit, 'igm');
    
     var hits = str.match(re_full);
     for (var hit in hits) {
      hit = hits[hit];
      var amounts = hit.match(re_number);
      var unit = hit.match(re_unit);
      unit = unit[0];
    
      for (var unit2 in units) {
       for (var alias in units[unit2][0]) {
        if (units[unit2][0][alias] == unit) {
         unit = [units[unit2][1], units[unit2][2]];
        }
       }
      }
    
      // Catch "1 1/2" as addition rather than a range
      if (amounts.length == 2 && hit.indexOf(amounts.join(' ')) > -1) {
       // Exception: "one 29 oz can of whatever" is just 29 oz instead of one+29=30
       if ((amounts[0] == 'one' && strtonumber(amounts[1]) >= 1) || amounts[0] == 'a' || amounts[0] == 'an') {
        amounts[0] = amounts[1];
        delete amounts[1];
       }
       else {
        amounts = [strtonumber(amounts[0]) + strtonumber(amounts[1])];
       }
      }
    
      var replacement = '';
      var separator = '';
      for (var amount in amounts) {
       amount = strtonumber(amounts[amount]);
    
       replacement += separator + unit[0](amount, unit[1]);
       separator = '-';
      }
    
      if (debug) {
       console.log('Matched:', hit, 'Amount:', amount, 'Unit:', unit, 'Replacement:', replacement);
      }
    
      str = str.replace(hit, replacement);
     }
     return str;
    }
    
    //console.log(fixSizes(test));
    document.documentElement.innerHTML = fixSizes(document.documentElement.innerHTML);