Monokot Server 1.x
  • What is Monokot Server?
  • Quickstart
  • 🐸Basics
    • Supported OS and Hardware
    • Installation
    • Licensing
    • OPC UA
      • UA TCP Endpoint
      • UA Settings
      • Client Certificates
      • Aliases
      • Access to Object Settings
      • Troubleshooting
    • Security Certififcate
    • Users & Roles
    • Administrator GUI
      • Event Log
      • Users in Monokot Server Administrator
      • Roles in Monokot Server Administrator
    • Startup Parameters
  • 🦊Tags & Devices
    • Devices
      • Diagnostics
      • Devices in the Monokot Server Administrator
    • Tags
      • Parameters
      • Change Trigger
      • Tags in Monokot Server Administrator
        • Go Online
        • Group Action
        • Import & Export
    • Modbus Connectivity
      • Parameters
      • Addressing
      • Diagnostics
    • Siemens Connectivity
      • Parameters
      • Addressing
      • Access to DBs area in S7-1200/S7-1500
    • IEC 60870-5-104 Connectivity
      • Parameters
      • Addressing
      • Time Conversion
      • Diagnostics and Commands
    • OPC UA Connectivity
      • Parameters
      • Addressing
      • Diagnostics
      • How to: Importing OPC UA items
      • How to: Pulling Security Certificate
    • InfluxDB Connectivity (Connector)
      • Parameters
      • Addressing
      • Query Result and Data Mapping
      • Diagnostics
      • How to: Configure for InfluxDB 2.x
    • SNMP Connectivity
      • Parameters
      • Addressing
      • UDP Considerations
  • 🐺Time Series & Stores
    • Stores
      • Backlog
      • Diagnostics
      • Stores in Monokot Server Administrator
    • Time Series
      • Parameters
      • Deadband
      • Sampling
      • Last Sample Repeat
      • Time Series in Monokot Server Administrator
        • Group Action
        • Import & Export
    • InfluxDB Connectivity (Store)
      • Parameters
      • Addressing
      • Data Structure
      • About Metadata
      • Diagnostics
      • How to: Configure for InfluxDB 2.x
    • PostgreSQL Connectivity
      • Parameters
      • Addressing
      • Database Design
      • Data Compression
    • REST Connectivity
      • Parameters
      • Addressing
      • Message Script
      • RestRequestMessage
      • DataContext
      • TimeSeries
  • 🐻Scripts
    • Overview
    • Expression
      • Parameters
      • Import & Export
      • Go Online
    • Programming Examples
      • How to: Calculate Arithmetic Mean
      • How to: DoNothing
      • How to: Writing to Tag
      • How to: Inverting Bits
      • How to: Execute SQL
      • How to: Run Ping
      • How to: Do Simulation
      • How to: String Formatting
      • How to: OPC UA Method
      • How to: Initialize Device Settings from File
    • API
      • Bundle
      • BundlePair
      • Context
      • DataMap
      • DataMapPair
      • DataTriggerInfo
      • Expression
      • MosCrypto
      • MosDirectories
      • MosFiles
      • MosOdbc
      • MosOdbcReader
      • MosProcess
      • MosProcessExecuteResult
      • MosText
      • MosUtils
      • ValueState
Powered by GitBook
On this page
  1. Scripts
  2. Programming Examples

How to: String Formatting

PreviousHow to: Do SimulationNextHow to: OPC UA Method

Last updated 2 years ago

The guide shows how to create an expression that will return a formatted string. Before starting, create a local Modbus device, a tag with the name source_tag and the data format FLOAT (32-bit floating point).

DISCLAIMER

You can just use the format function from . This guide is given for an example of working with scripts and modules

Open Monokot Server Administrator, double-click Scripts on the Server Explorer pane and go to the Modules tab. Click the New Module button and name the module Sprintf. Insert the following code into the code editor:

// Return a formatted string 
function sprintf() {     
    var regex = /%%|%(\d+\$)?([-+\'#0 ]*)(\*\d+\$|\*|\d+)?(\.(\*\d+\$|\*|\d+))?([scboxXuidfegEG])/g;
    var a = arguments, i = 0, format = a[i++];

    // pad()
    var pad = function (str, len, chr, leftJustify) {
        if (!chr) { chr = ' '; }
        var padding = (str.length >= len) ? '' : Array(1 + len - str.length >>> 0).join(chr);
        return leftJustify ? str + padding : padding + str;
    };

    // justify()
    var justify = function (value, prefix, leftJustify, minWidth, zeroPad, customPadChar) {
        var diff = minWidth - value.length;
        if (diff > 0) {
            if (leftJustify || !zeroPad) {
                value = pad(value, minWidth, customPadChar, leftJustify);
            } else {
                value = value.slice(0, prefix.length) + pad('', diff, '0', true) + value.slice(prefix.length);
            }
        }
        return value;
    };

    // formatBaseX()
    var formatBaseX = function (value, base, prefix, leftJustify, minWidth, precision, zeroPad) {
        // Note: casts negative numbers to positive ones
        var number = value >>> 0;
        prefix = prefix && number && { '2': '0b', '8': '0', '16': '0x'}[base] || '';
        value = prefix + pad(number.toString(base), precision || 0, '0', false);
        return justify(value, prefix, leftJustify, minWidth, zeroPad);
    };

    // formatString()
    var formatString = function (value, leftJustify, minWidth, precision, zeroPad, customPadChar) {
        if (precision != null) {
            value = value.slice(0, precision);
        }
        return justify(value, '', leftJustify, minWidth, zeroPad, customPadChar);
    };

    // doFormat()
    var doFormat = function (substring, valueIndex, flags, minWidth, _, precision, type) {
        var number;
        var prefix;
        var method;
        var textTransform;
        var value;

        if (substring == '%%') { return '%'; }

        // parse flags
        var leftJustify = false, positivePrefix = '', zeroPad = false, prefixBaseX = false, customPadChar = ' ';
        var flagsl = flags.length;
        for (var j = 0; flags && j < flagsl; j++) {
            switch (flags.charAt(j)) {
                case ' ': positivePrefix = ' '; break;
                case '+': positivePrefix = '+'; break;
                case '-': leftJustify = true; break;
                case "'": customPadChar = flags.charAt(j + 1); break;
                case '0': zeroPad = true; break;
                case '#': prefixBaseX = true; break;
            }
        }

        // parameters may be null, undefined, empty-string or real valued
        // we want to ignore null, undefined and empty-string values
        if (!minWidth) {
            minWidth = 0;
        } else if (minWidth == '*') {
            minWidth = +a[i++];
        } else if (minWidth.charAt(0) == '*') {
            minWidth = +a[minWidth.slice(1, -1)];
        } else {
            minWidth = +minWidth;
        }

        // Note: undocumented perl feature:
        if (minWidth < 0) {
            minWidth = -minWidth;
            leftJustify = true;
        }

        if (!isFinite(minWidth)) {
            throw new Error('sprintf: (minimum-)width must be finite');
        }

        if (!precision) {
            precision = 'fFeE'.indexOf(type) > -1 ? 6 : (type == 'd') ? 0 : undefined;
        } else if (precision == '*') {
            precision = +a[i++];
        } else if (precision.charAt(0) == '*') {
            precision = +a[precision.slice(1, -1)];
        } else {
            precision = +precision;
        }

        // grab value using valueIndex if required?
        value = valueIndex ? a[valueIndex.slice(0, -1)] : a[i++];

        switch (type) {
            case 's': return formatString(String(value), leftJustify, minWidth, precision, zeroPad, customPadChar);
            case 'c': return formatString(String.fromCharCode(+value), leftJustify, minWidth, precision, zeroPad);
            case 'b': return formatBaseX(value, 2, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'o': return formatBaseX(value, 8, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'x': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'X': return formatBaseX(value, 16, prefixBaseX, leftJustify, minWidth, precision, zeroPad).toUpperCase();
            case 'u': return formatBaseX(value, 10, prefixBaseX, leftJustify, minWidth, precision, zeroPad);
            case 'i':
            case 'd':
                number = parseInt(+value, 10);
                prefix = number < 0 ? '-' : positivePrefix;
                value = prefix + pad(String(Math.abs(number)), precision, '0', false);
                return justify(value, prefix, leftJustify, minWidth, zeroPad);
            case 'e':
            case 'E':
            case 'f':
            case 'F':
            case 'g':
            case 'G':
                number = +value;
                prefix = number < 0 ? '-' : positivePrefix;
                method = ['toExponential', 'toFixed', 'toPrecision']['efg'.indexOf(type.toLowerCase())];
                textTransform = ['toString', 'toUpperCase']['eEfFgG'.indexOf(type) % 2];
                value = prefix + Math.abs(number)[method](precision);
                return justify(value, prefix, leftJustify, minWidth, zeroPad)[textTransform]();
            default: return substring;
        }
    };

    return format.replace(regex, doFormat);
}

Press Ctrl + Enter to apply the change in the code editor.

Go to the Expressions tab and click the New Expression button. For the expression that appeared, set the name Message and specify the data type STRING. Insert the following code into the expression code editor:

var val = context.data['source_tag_trig'].state.value;
return sprintf('Formatted number: %.3f', val);

Press Ctrl + Enter to apply the change in the code editor. Go to the Triggers tab and click Add Data.... Select the previously created tag (source_tag) as the data source for the trigger. Enter source_tag_trig as the name (key) of the trigger.

Go to the Imports tab and click the checkbox of the Sprintf module.

In order for the changes to take effect on the server, click the Sync button. If you switch to Go Online mode, you will see a picture similar to the following (in my case, the number 0.123456 is displayed).

By default, the ECMAScript 5 standard does not provide a string formatting function, but since there are a huge number of developers who code in JavaScript, most typical tasks have already been solved, as in this case. The sprintf function () has existed for several years now and is analogous to the PHP sprintf function.

🐻
MosText
https://github.com/alexei/sprintf.js