Scenerio
一个小需求,我有一个文本文件/一段文本,其中混杂有多组不尽相同的正整数(暂时不考虑负数/小数/科学计数法表示的数值)。 我需要:
- 提取出其中所有的数字,得到一个数值的集合。
- 对出现的数字去重,得到一个数值的集合。
- 对去重后的数值集合排序,得到最终结果。
demo
在一段文本中随意插入一些数值,作为demoStringValue。
孤始举孝廉,年少,自以本非岩穴知名之士,恐为海内人之所见凡愚,欲为一郡守,好作政教,以建立名誉,使世士明知之;故在济南,始除残去秽,平心选举,违迕诸常侍。以为强豪所忿,2914365765恐致家祸,故以病还。 去官之后,年纪尚少,顾视同岁中,年有213五十,未名为老。内自图之,从此却去二十年,待天下清,乃与同岁中始举者等耳。故以四时归乡里,于谯东五十里筑精舍,欲秋夏读书,冬春射猎,求底下之地,欲以泥水自蔽123,绝宾客往来之望。然不能得如意。234353 后徵为都尉,迁典军校尉435,意遂更欲为国家讨贼立功,欲望封侯作征西将军897,然后题墓道言“汉故征西将军曹侯之墓”,此其志也。而遭值董卓之难,兴举义兵。是时合兵能多得耳,然常自损,不欲多之;所以然者,多兵意盛,与强4敌争,倘更为祸始。故3汴水之战数千,后还到扬州更募,亦复不过三千人,此其本志有24限也。 后领兖州,破降黄巾三十万众。又袁术僭号于九江,下皆称臣,名门曰建号门,衣4被皆3423为天子之制,两妇预争为皇后67。志计已定,人有劝术使遂即帝位,露布天下,答言“曹公尚在,未可也”。后孤讨禽其四将,获其人众,遂使术穷亡解沮,发病而死。及至袁绍据河北,兵势强盛,孤自度势,实不敌之;但计投死为国,以义灭身87,足垂于后。幸而破绍,枭其二子。又刘表自以为宗室,包藏342奸心,乍前乍却,以观世事,据有当州,孤复45645定之,遂平天下。身为宰相,人臣之贵已极,意望已过矣)。 今孤言此,若为自大,欲人言尽,故98706无讳7耳。设使国家无有孤,1不知当几人称帝,几人称王!45或者2342人见2孤强盛,又性不信天命之事,恐私心相评,言有不逊之志,妄相忖度,每用耿耿。齐桓、晋文所以垂称至今日者,以其兵势广大,犹能奉事周室也8。《论语》云:“三分123天下有其二,以服事殷,周76之德可谓至德矣。”夫能以大事小也1。昔乐毅走赵,赵王欲与之图燕。乐毅伏而垂泣,对曰:“臣事昭王,犹事大王;臣若获戾,放在他国,没世然后已,不4654忍谋赵之徒隶,况燕后嗣乎!”胡亥之杀蒙恬也,恬曰:“自吾先人及至子孙,积信于秦三世矣;今臣将兵三十余万,其势足以背叛,然自知必死而守义者,不敢辱先人之教以忘先王也。”孤每读此二人书,未尝不怆然流涕也。孤祖、父以至孤身,皆当亲重之任,可谓见信者矣,以及子桓兄弟,过于三世矣。46547 孤非徒对诸君说此也,常以语245妻妾,皆令1231深知此意。孤谓之言:“顾我万年之后,汝曹皆当出嫁,欲令传道我0心,使他人皆知之。”孤此言皆肝鬲之要也。所以勤勤恳恳叙心腹者,见周公有《金縢》之书以6自明,恐人不信之故。然欲孤便尔委捐所典兵众,以还执76事,归就6786武平侯国,实不可也。何者456?诚恐己离兵为人所祸也。既为子孙计,又己败则国家倾危,是以不得慕虚名而处实祸,此所不得为也。前朝恩封三子为侯,固辞不受,今更欲受之,非欲复以为荣,欲以为外援,为万安计。 孤闻介推之避晋封,申胥之逃楚赏,未尝不舍书而叹,有以自省也。奉国威灵,仗钺征伐,推弱67567以克强,处小而禽大。意之所图,动无违事,心之所虑,何向不济,遂荡平天下,不辱主命。可谓天助汉室,非人力也。然封兼四县,食户三5万,何德堪之!江湖未静,不可让位;至于邑土,可得而辞。今上还阳夏、柘、苦三县户二万,但食武平万户,且以分损谤议,少减孤之责也。 (出自《三国志?武帝纪》裴松之注本。)[1]
两行javascript代码从已有文本变量中提取/处理数值数据
a = `demoStringValue`
[...new Set(a.match(/\d+/g))].sort((a, b) => a-b)
第一行定义字符串变量的代码量会比较多。 所以我一般把它单独拆开放一行。 如果代码有修改,这一行不用动。
浏览器控制台 JavaScript API测试
从一串文本中按照某种模式提取出匹配的子字符串 String.prototype.match(regexp)
先用反引号包围我们的字符串,定义一个字符串变量a。(使用反引号不用考虑原本字符串内容中的单引号/双引号转义)。
String.prototype.match(regexp) 用于:在字符串对象中,按照给定的正则表达式模式,依次查找匹配成功的子字符串。 注意正则表达式的flag:g 表示global,在字符串全局去匹配。不加的话,只匹配到第一个,就会马上返回。
数组去重 Array–>Set
Array–>Set: 数组对象直接作为Set构造方法的入参,可以对Array中的元素去重。 var setObj = new Set(arrayObject) Set–>Array: 有好几种方法。
var set = ...;
var arr1 = [...setObj]; // 解构赋值
var arr2 = new Array(...setObj); // 解构赋值 + Array 构造方法
var arr3 = new Array([...setObj]);
数组排序 Array.prototype.sort(compareFn)
Array.prototype.sort(compareFn) 数组对象本来就有一个sort方法。 但是sort方法默认的实现不一定能满足需求。 比如在本例中,该数组实际上是一个 String[] ,只不过每个String元素的值是数值字面量。 但是sort方法依然按照字符串的比较方法 对元素进行排序(排序规则取决于当前的字符集 Character Set 和使用的校对集 collation)。 可以自己传入一个 var compareFn = function(a, b) { return a - b; } ,按照数值规范对元素排序。
流程总结
a = `......`;
a.match(/\d+/g);
new Set(a.match(/\d+/g));
[...new Set(a.match(/\d+/g))];
[...new Set(a.match(/\d+/g))].sort();
[...new Set(a.match(/\d+/g))].sort((a, b) => a-b);
共6行:
- 使用反引号,用将要处理的文本对其赋值;
- 使用
String.prototype.match(regexp) 提取出其中的数值字符串(整数); - Array --> Set ;
- Set --> Array
- Array.prototype.sort() 使用默认的sort规则。
- 自定义compareFn规则。
Other case
不自己指定 compareFn ,有什么办法?
Array.prototype.sort() 不能满足需求,但是: Uint32Array.prototype.sort() 可以直接满足需求。
new Uint32Array([...new Set(a.match(/\d+/g))]).sort()
如果要提取的数值不止正整数,还有小数/其他格式,如何操作?
/\d+/g 也可以写成new RegExp('\d+', 'g') 或new RegExp(/\d+/, 'g') ,表示至少一位的数字字符0~9 ,global模式。 去查 javascript 正则表达式规则 替换/\d+/g 你需要什么规则,即用什么规则。
数据量
如果你要操作的文本量很大,当然不适合直接在浏览器控制台这样写。 如果你需要把这个过程固化 ,提供一个输入,并输出到指定位置,浏览器控制台也只能帮你测试/验证语法。
增加要处理的数据量/将程序处理流程固化,到最后要调用的基础API不会变。 会变的只是其他节点。 浏览器控制台只是用于小数据量的文本处理+语法测试/猜想验证。
除了 Uint32Array 还有其他什么类似的类型可以达到类似的排序效果
有啊,而且还有好几种,见MDN TypedArray 按照单个变量所需字节数递增,依次有 Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array, BigIntArray, BigUint64Array 按照你的需求,不同情况下分别选择最适合的类型。
|