How to replace all Roman numbers in a string for the Arabic equivalent?

I have a list of all Shakespeare's sonnets, and I perform the search function of each sonnet. However, I want to be able to search for them using Arabic numbers (for example, "/ sonnet 122". TXT is formatted as follows:

I This is a sonnet II This is a second sonnet 

I am using node right now to try to do this, but I tried from yesterday to no avail. My last attempts yesterday used the replace method as such:

 'use strict'; //require module roman-numerals, which converts roman to arabic var toArabic = require('roman-numerals').toArabic; //require file-handling module var fs = require('fs'); fs.readFile('sonn.txt', 'utf8', function (err,data) { if (err) { console.log(err); } else { var RN = /[AZ]{2,}/g; var found = data.match(RN); //finds all roman numbers and puts them in an array var numArr = []; for (var i = 0; i < found.length; i++ ){ numArr.push(toArabic(found[i])); //puts all arabic numbers in numArr } for (var e = 0; e < found.length; e++){ data.replace(found, found.forEach((x, i)=> { toArabic(x) } }); 

Then I tried replacing them:

 data.replace(found, function(s, i){ return numArr[i]; }); 

Then I tried to use a for loop. I did not save this code, but it was something like:

 for(var i=0;i<found.length;i++){ data.replace(found, numArr[i]); } 

The last code replaces each number, and then erases the data and replaces the next number as follows:

 replace(abc, 123) -> 1bc, a2c, ab3 

How to make it repeat every event in the data and save it? Then saving it to the new txt should be easy.

(Also, my RegExp finds only plural character numbers to avoid replacing the single I that can be found at the end of the line.)

+7
javascript
source share
3 answers

You need to write the replaced string back, and you can use the callback for replace()

 'use strict'; var toArabic = require('roman-numerals').toArabic; var fs = require('fs'); fs.readFile('sonn.txt', 'utf8', function (err,data) { if (err) { console.log(err); } else { data = data.replace(/[AZ]{2,}/g, function(x) { return toArabic(x); }); } }); 

Here are a few more regular expressions to match the novel

+1
source share

If you use String.prototype.replace , you can use your regular expression and custom replace function. You just need to return the value to use as a replacement, which is what toArabic does.

 var data = 'I\n\nThis is a sonnet\n\nII\n\nThis is a second sonnet'; //======================== var toArabic = (function () { var forEach = Array.prototype.forEach; /** * Converts a roman number to its arabic equivalent. * * Will throw TypeError on non-string inputs. * * @param {String} roman * @return {Number} */ function toArabic (roman) { if (('string' !== typeof roman) && (!(roman instanceof String))) throw new TypeError('toArabic expects a string'); // Zero is/was a special case. I'll go with Dionysius Exiguus on this one as // seen on http://en.wikipedia.org/wiki/Roman_numerals#Zero if (/^nulla$/i.test(roman) || !roman.length) return 0; // Ultra magical regexp to validate roman numbers! roman = roman.toUpperCase().match(/^(M{0,3})(CM|DC{0,3}|CD|C{0,3})(XC|LX{0,3}|XL|X{0,3})(IX|VI{0,3}|IV|I{0,3})$/); if (!roman) throw new Error('toArabic expects a valid roman number'); var arabic = 0; // Crunching the thousands... arabic += roman[1].length * 1000; // Crunching the hundreds... if (roman[2] === 'CM') arabic += 900; else if (roman[2] === 'CD') arabic += 400; else arabic += roman[2].length * 100 + (roman[2][0] === 'D' ? 400 : 0); // Crunching the tenths if (roman[3] === 'XC') arabic += 90; else if (roman[3] === 'XL') arabic += 40; else arabic += roman[3].length * 10 + (roman[3][0] === 'L' ? 40 : 0); // Crunching the...you see where I'm going, right? if (roman[4] === 'IX') arabic += 9; else if (roman[4] === 'IV') arabic += 4; else arabic += roman[4].length * 1 + (roman[4][0] === 'V' ? 4 : 0); return arabic; }; return toArabic; })(); //==================== var RN = /[AZ]{1,2}(?=\n)/g; var newData = data.replace(RN, toArabic); document.body.innerText = newData; 
+1
source share

This view is best handled as stream transform . The old node stream conversion library is a bit funky for initialization, but it does the job very quickly and well. Here is a working example using the replace function that @adeneo wrote above.

 var stream = require('stream'); var util = require('util'); var toArabic = require('roman-numerals').toArabic; var fs =require('fs'); var rstream = fs.createReadStream('sonnets.txt'); var wstream = fs.createWriteStream('sonnets.transformed.txt'); // node v0.10+ use native Transform, else polyfill var Transform = stream.Transform || require('readable-stream').Transform; function Converter(options) { // allow use without new if (!(this instanceof Converter)) { return new Converter(options); } // init Transform Transform.call(this, options); } util.inherits(Converter, Transform); Converter.prototype._transform = function (chunk, enc, cb) { //transform the chunk var data = chunk.toString().replace(/[AZ]{2,}/g, function(x) { return toArabic(x); }); this.push(data); //push the chunk cb(); //callback }; // try it out var converter = new Converter(); // now run it on the whole file rstream .pipe(converter) .pipe(wstream) // writes to sonnets.transformed.txt .on('finish', function () { // finished console.log('done transforming'); }); 

This is pretty well described here: http://codewinds.com/blog/2013-08-20-nodejs-transform-streams.html and here with more modern examples using lib2 conversion https://github.com/substack/stream -handbook

+1
source share

All Articles