这里主要是记录一些平时用到的一些代码片段, 不定时更新。

Javascript

统计数组中每个元素出现的次数

const array = [1, 2, 3, 1, 2, 1];
const count = {};

array.forEach(item => {
  if (count[item]) {
    count[item]++;
  } else {
    count[item] = 1;
  }
});

console.log(count);
// 输出: {1: 3, ... }

集合运算

function intersection(setA, setB) {
    return new Set([...setA].filter(x => setB.has(x)));
}

function union(setA, setB) {
    return new Set([...setA, ...setB]);
}

function difference(setA, setB) {
    return new Set([...setA].filter(x => !setB.has(x)));
}

问卷星-生成随机数据

// 获取问卷星数据
const qaq_containers = [...document.getElementById('divQuestion').querySelectorAll('.ui-field-contain')];
let qaqs = qaq_containers.map(qc => {
    // console.log(qc.querySelector('.field-label').innerText);
    // console.log( (qc.querySelector('.ui-controlgroup') || qc.querySelector('.ui-input-text') ).innerText);
    let q = qc.querySelector('.field-label').innerText;
    let a_container = qc.querySelector('.ui-controlgroup') || qc.querySelector('.ui-input-text');
    let a = a_container.innerText.replace(/([ABCDEF]\.?|[ABCDEF] ?)/g, '').split('\n');
    return [q, a];
})

// 初始化每个题目的答案概率(每个答案取相等概率), 对于特定的题目, 自行设定概率. 
let weights = qaqs.map(qaq => qaq[1].map(a => 1/qaq[1].length) );
weights[2] = [0.3, 0.3, 0.35, 0.05];
weights[9] = [0.8, 0.1, 0.1];
weights[19] = [0.8, 0.1, 0.1];
weights[22] = [0.7, 0.1, 0.1, 0.1];
weights[24] = [0.1, 0.8, 0.1];

// 根据概率生成数据
const N = 1500;
const num_qaqs = qaqs.length;
let total_data = new Array(N);
for(j=0; j<N; j++) {
    let data = new Array(num_qaqs);
    for(i=0; i<num_qaqs; i++) {
        let r = Math.random();
        let w = 0;
        for(k=0; k<weights[i].length; k++) {
            w += weights[i][k];
            if(r < w) {
                data[i] = qaqs[i][1][k];
                break;
            }
        }
        total_data[j] = data;
    }    
}

// 生成每个题目的答案的统计数据
let count_arr = new Array(num_qaqs);
for(s=0; s<num_qaqs; s++) {
    let array = total_data.map(data => data[s]);
    let count = {};

    array.forEach(item => {
        if (count[item]) {
            count[item]++;
        } else {
            count[item] = 1;
        }
    });

    count_arr[s] = count;
    // console.log(s+1);
    // console.log(count);
    
}

// 保存数据到txt文件(复制txt文件内容到excel即可生成)
const str_data = total_data.map(data => data.reduce((i, j) => i + '	' + j)).reduce((i, j) => i + '\n' + j);
function download(filename, text) {
  let element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);
  element.style.display = 'none';
  document.body.appendChild(element);
  element.click();
  document.body.removeChild(element);
}
 
download("data.txt", str_data);

处理参考文献

良好的习惯是保持每条参考文献都是如下格式(下面我们的操作都以此为基础)

\bibitem{name}
authors.
title.
journal ...

即每个参考文献按索引名, 作者, 标题, 刊信息分为四行,同时要求两个参考文献之间空一行。 这样做的好处在于方便统一修改。

处理人名

不同期刊, 参考文献人名格式也不尽相同, 每次修改总是很麻烦(这里指使用\bibitem环境). 主流期刊的人名格式([]表示可能有空格)以及他们对应的正则匹配

M.[]X. Jia, M.[]X. Jia     <=======>     /([A-Z]\. ?)+ ([a-z]+ )?[A-Z][^\s,]+/g
Jia, M.[]X., Jia, M.[]X.   <=======>     /([a-z]+ )?[A-Z][^\s,]+, ([A-Z]\. ?)+/g
Jia M X, Jia M X           <=======>     /([a-z]+ )?[A-Z][^\s,]+ ([A-Z]\. ?)+/g

首先我们对参考文献进行处理, 得到文献作者列表

var bib = document.getElementById('input').value.split(/\n/).filter( a => a.match('[a-z]') );
var authors = [];
for(let i=1; i<bib.length; i=i+4) authors.push( bib[i].replace(/and /, ', ') );

然后根据不同的作者格式来匹配, 正常情况下, 匹配完成后, 只会剩下标点符号, 否则匹配失败.

// 3 ---> 2;
const regreps = [
	'',
	'([A-Z]\\. ?)+ (([a-z]+ )?[A-Z][^\\s,]+)',
	'(([a-z]+ )?[A-Z][^\\s,]+), ([A-Z]\\. ?)+',
	'(([a-z]+ )?[A-Z][^\\s,]+) ([A-Z] ?)+',
];
const index_old = 3, 
	  index_new = 2,
      regrep_old = new RegExp( regreps[index_old] ),
	  regrep_new = new RegExp( regreps[index_new] ),
	  regrep_old_g = new RegExp( regreps[index_old], 'g');

var authors_match = authors.map( a => a.match( regrep_old_g ) )
var remaining = authors.map( a => {
	let match = a.match( regrep_old_g );
	match.forEach( m => a = a.replace(m, '') );
	return a.match(/[A-Za-z]/);
})
for( let i=0; i<authors.length; i++) {
	if( remaining[i] === null ) {
		authors_match[i].map( a => a.match(regrep_old) )
	}
}

按照引用顺序排列参考文献

整理论文的参考文献时,没有使用bib文件, 想要按照引用的顺序来重新排列已经弄好的参考文献。 这里我们使用 Sublime-text 3 编辑器。 首先匹配tex文件中引用的文献索引名

\\cite{.*?}

然后对其处理, 得到全部文献索引名构成的字符串数组(这里要求文献索引名由数字,字母,下划线,短横杠组成)

cites_ = `
\cite{...}
...
\cite{...}
`.replaceAll("cite", "").match(/[\w-]+/g)  // [ "ref1", "ref2", ... ]

我们还要去除里面重复的。 对于多次引用的, 只需要保留第一个

cites = [];
for (let cite of cites_) {
	if (cites.indexOf(cite) < 0) {
		cites.push(cite);		
	}
}

接下来处理参考文献。 这里我们将参考文献复制到Maple-Latex中, 然后利用javascript对其处理并重新排列

refs_ = $$('#input')[0].value.split(/\\bibitem/g).slice(1);

// 按索引名生成字典
refs = {};
for (let ref of refs_) {
	let abbr = ref.match(/^{(.*?)}/)[1]
	refs[abbr] = "\\bibitem" + ref;
};
// 根据引用索引名顺序排列参考文献
refs_ = '';
for (let cite of cites) {
	refs_ += refs[cite] + '\n';
}

$$('#input')[0].value = refs_.replaceAll('\n\n', '\n');

这样就可以了。

按照姓氏字母排列参考文献

同样地, 我们可以对参考文献按照姓氏字母排列。 这只需对参考文献操作即可(这里参考文献最好能够符合4行格式)。 使用javascript对其处理

// 拆分参考文献并获取作者列表
refs_ = $$("#input")[0].value.split(/\\bibitem/).slice(1).map( r => "\\bibitem" + r );
authors_ = refs_.map( r => r.match(/} *\n(.*?)\n/)[1] )
		   		.map( a => a.split(/(,| and)/)
		   			.filter( a => (a !== ",") && (a !== " and") && (a.replace(/ +/, '') !== "") ) 
		    	);

这样处理以后, 会根据文献格式得到不同的结果

"姓, 名, 姓, 名"  => ["姓", "名", "姓", "名"]
"名, 姓, 名, 姓"  => ["名", "姓", "名", "姓"]
"姓 名, 姓 名"  => ["姓 名", "姓 名"]
"名 姓, 名 姓"  => ["名 姓", "名 姓"]

因为排序只比较姓氏, 因此, 我们只需获取每个参考文献的姓氏, 然后重排即可。 首先姓氏相加

authors = authors_.map( a => a.map( a => a.match(/([a-z]{2,} )?[A-Z][a-zA-Z]+/)[0] ) ).map( a => a.reduce( (i, j) => i+j) ) 

然后

refs = {};
// 首先生成字典, 作者重复的, 加索引加以区分
for (i=0; i<refs_.length; i++) {
	if ( authors.slice(0, i).indexOf( authors[i] ) > -1 ) {
		authors[i] += i;
	}
	refs[ authors[i] ] = refs_[i];
}
// 重排, 然后根据作者顺序排列参考文献
authors = authors.sort();
refs_ = '';
for (let author of authors) {
	refs_ += refs[author] + '\n';
}

$$('#input')[0].value = refs_.replaceAll('\n\n', '\n');