-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalignWords.js
95 lines (64 loc) · 2.32 KB
/
alignWords.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
function alignWords(lines, options = {}) {
const {
alignmentError = false,
groupWith = `[]`,
separator = `spaces`,
} = options;
const [leftBracket, rightBracket] = groupWith.trim().split(``);
let wordRegExp = /(?<bracketed>\S*\[.*?\]\S*)|(?<unbracketed>\S+)/gu;
if (groupWith !== `[]`) {
const pattern = wordRegExp.source
.replace(`\\[`, `\\${leftBracket}`)
.replace(`\\]`, `\\${rightBracket}`);
wordRegExp = new RegExp(pattern, `gu`);
}
lines = Array.from(lines);
lines = lines.map(line => line.trim());
lines = lines.map(line => [...line.matchAll(wordRegExp)].map(([match]) => match));
if (alignmentError === true) {
const sameLength = lines.every(line => line.length === lines[0].length);
if (!sameLength) throw new Error(`AlignmentError`);
}
if (separator === `tabs`) {
lines = lines.map(line => line.join(`\t`).trim());
} else {
const indexOfLongestLine = lines.reduce((longestIndex, line, i) => {
if (!line.length) return longestIndex;
if (line.length > longestIndex) return i;
return longestIndex;
}, 0);
const longestLine = lines[indexOfLongestLine];
longestLine.forEach((word, i) => {
const longestWordLength = lines.reduce((len, line) => {
const w = line[i];
if (!w) return len;
const charLength = getCharLength(w);
if (charLength > len) return charLength;
return len;
}, 0);
lines.forEach(words => {
const w = words[i];
if (!w) return;
const charLength = getCharLength(w);
const padLength = longestWordLength + (w.length - charLength);
words[i] = w.padEnd(padLength);
});
});
lines = lines.map(line => line.join(` `).trim());
}
return lines;
}
/**
* Gets the length of a string in characters rather than unicode points
* @param {String} str The string to find the length of
* @return {Integer} The character length of the string
*/
function getCharLength(str) {
// search for non-combining character followed by combining character
const combiningRegExp = /(?<char>\P{Mark})(?<combiner>\p{Mark}+)/gu;
// remove combining characters
str = str.replace(combiningRegExp, `$1`);
// get length, accounting for surrogate pairs
return Array.from(str).length;
}
export default alignWords;