3 回答

TA貢獻(xiàn)1797條經(jīng)驗(yàn) 獲得超6個(gè)贊
這應(yīng)該可以解決問題
const my_str = 'This is {startMarker} the string {endMarker} for {startMarker} example.{endMarker}';
const my_arr = my_str.split('{endMarker}').reduce((acc, s) =>
s.split('{startMarker}').map((a,i) =>
a && acc.push({
marker: i ? true : false,
value: a.trim()}))
&& acc,[]);
console.log(my_arr)

TA貢獻(xiàn)1851條經(jīng)驗(yàn) 獲得超4個(gè)贊
只是因?yàn)槟切仑暙I(xiàn)者......
interface MarkedString {
marker: boolean
value: string
}
function markString(text: string): MarkedString[] {
let match: RegExpExecArray | null
const firstMatch = text.slice(0, text.indexOf('{') - 1)
const array: MarkedString[] = firstMatch.length > 0 ? [
{ marker: false, value: firstMatch }
] : []
while ((match = /\{(.+?)\}/g.exec(text)) !== null) {
if (!match) break
const marker = match[0].slice(1, match[0].slice(1).indexOf('}') + 1)
const markerEnd = match.index + match[0].length
const value = text.slice(markerEnd ,markerEnd + text.slice(markerEnd).indexOf('{')).trim()
if (value === '') break
if (marker === 'startMarker') {
array.push({ marker: true, value })
} else if (marker === 'endMarker') {
array.push({ marker: false, value })
}
text = text.slice(markerEnd + value.length + 1)
}
return array
}

TA貢獻(xiàn)1862條經(jīng)驗(yàn) 獲得超6個(gè)贊
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const extract = (start, end, str) => Array.from(
? str.matchAll(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`),
? ([, text, mark]) => ({
? ? marker: mark === end,
? ? value: text.trim()
? })
);
console.log(extract(
? "{startMarker}",
? "{endMarker}",
? "This is {startMarker} the string {endMarker} for {startMarker} example. {endMarker}"
));
解釋
正則表達(dá)式
我們發(fā)送以兩個(gè)標(biāo)記之一結(jié)尾的文本段。我們可以提取包括標(biāo)記在內(nèi)的每個(gè)部分。
This is {startMarker} the string {endMarker}?
^______^^___________^^__________^^_________^
| text? ? ? ?mark? ?||? ?text? ? ? ? mark? |
^___________________^^_____________________^
? ? ? ?section? ? ? ? ? ? ? ?section
文本將成為value結(jié)果對(duì)象的文本,可以檢查標(biāo)記段是否是{endMarker}為了生成true或false用于結(jié)果對(duì)象。
因此,如果我們能夠正確提取段和節(jié),結(jié)果是:
result = {
? marker: marker === "{endMarker}",
? value: text.trim()
}
可以為我們執(zhí)行此操作的正則表達(dá)式是:
/(.+?)(\{startMarker\}|\{endMarker\}|$)/g
(.+?)
將匹配并捕獲文本段(\{startMarker\}|\{endMarker\}|$)
將匹配并提取文本段末尾的標(biāo)記。它還匹配行尾,以防最后一個(gè)標(biāo)記后有更多文本,就像您有for {startMarker} example. {endMarker} more text here
一代
更一般地說,我們可以采用任何字符串作為開始和結(jié)束標(biāo)記,然后對(duì)它們進(jìn)行轉(zhuǎn)義以確保它們字面匹配,即使其中存在像.
或 之類的元字符*
。
const?escapeRegex?=?s?=>?s.replace(/[.*+\-?^${}()|[\]\\]/g,?"\\$&");
這樣我們就可以將start
and作為字符串并使用構(gòu)造函數(shù)生成end
正則表達(dá)式:RegExp
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const start = "{startMarker}";
const end = "{endMarker}";
const regex = new RegExp(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`, "g");
console.log(regex.toString());
匹配
該String#matchAll
方法將生成一個(gè)迭代器,其中包含應(yīng)用于字符串的正則表達(dá)式的所有匹配項(xiàng)。
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const extract = (start, end, str) => {
? const sequence = str.matchAll(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`);
??
? for(const result of sequence) {
? ? console.log(result);
? }
};
extract(
? "{startMarker}",
? "{endMarker}",
? "This is {startMarker} the string {endMarker} for {startMarker} example. {endMarker}"
);
該.matchAll()
方法接受字符串作為參數(shù),并使用RegExp
構(gòu)造函數(shù)自動(dòng)將其轉(zhuǎn)換為正則表達(dá)式,并進(jìn)一步自動(dòng)添加全局標(biāo)志。然而,TypeScript 目前似乎不允許這樣做 - 該方法的類型只允許一個(gè)RegExp
對(duì)象,因此僅對(duì)于 TypeScript(直到類型修復(fù))你必須調(diào)用
str.matchAll(new?RegExp(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`,?"g"))
轉(zhuǎn)換為數(shù)組
將可迭代對(duì)象轉(zhuǎn)換為數(shù)組的最簡(jiǎn)單方法是使用Array.from
.?它采用的第一個(gè)參數(shù)可以是可迭代的,并且會(huì)自動(dòng)轉(zhuǎn)換為數(shù)組。第二個(gè)參數(shù)是在將每個(gè)元素放入數(shù)組之前應(yīng)用的映射函數(shù)。
由于我們收到正則表達(dá)式匹配結(jié)果,我們可以使用此函數(shù)將它們直接轉(zhuǎn)換為所需的項(xiàng)目:
result => {
? const match = result[1];
? const marker = result[2];
? return {
? ? marker: marker === end,
? ? value: match.trim()
? };
}
這給了我們更詳細(xì)的版本:
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const extract = (start, end, str) => {
? return Array.from(
? ? str.matchAll(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`),
? ? result => {
? ? ? const match = result[1];
? ? ? const marker = result[2];
? ? ? return {
? ? ? ? marker: marker === end,
? ? ? ? value: match.trim()
? ? ? };
? ? }
? );
}
console.log(extract(
? "{startMarker}",
? "{endMarker}",
? "This is {startMarker} the string {endMarker} for {startMarker} example. {endMarker}"
));
然而,我們可以通過解構(gòu)來減少所需的代碼,它就變成了。
([, text, mark]) => ({
? marker: mark === end,
? value: text.trim()
})
這最終為我們提供了頂部的初始代碼(再次包含在內(nèi),以避免向上滾動(dòng)):
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
const extract = (start, end, str) => Array.from(
? str.matchAll(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`),
? ([, text, mark]) => ({
? ? marker: mark === end,
? ? value: text.trim()
? })
);
console.log(extract(
? "{startMarker}",
? "{endMarker}",
? "This is {startMarker} the string {endMarker} for {startMarker} example. {endMarker}"
));
關(guān)于 ES2020 兼容性的最后說明
String#matchAll來自 ES2020 規(guī)范。如果您當(dāng)前沒有瞄準(zhǔn)該目標(biāo)并且不想這樣做,您可以使用工作方式非常相似的生成器函數(shù)輕松推出自己的版本:
function* matchAll(pattern, text) {
? const regex = typeof pattern === "string"
? ? ? new RegExp(pattern, "g")? //convert to global regex
? ? : new RegExp(pattern);? ? ? //or make a copy of the regex object to avoid mutating the input
? ??
? let result;
? while(result = regex.exec(text)) //apply `regex.exec` repeatedly
? ? yield result;? ? ? ? ? ? ? ? ? //and produce each result from the iterator
}
這里唯一值得注意的遺漏是,String#matchAll如果傳入非全局正則表達(dá)式對(duì)象,則會(huì)拋出錯(cuò)誤。它仍然可以實(shí)現(xiàn),但我使用了一個(gè)稍短的實(shí)現(xiàn)來進(jìn)行說明。
使用自定義,matchAll您可以定位 ES2020 之前的版本,而無需填充
const escapeRegex = s => s.replace(/[.*+\-?^${}()|[\]\\]/g, "\\$&");
function* matchAll(pattern, text) {
? const regex = typeof pattern === "string"
? ? ? new RegExp(pattern, "g")
? ? : new RegExp(pattern);
? ??
? let result;
? while(result = regex.exec(text))
? ? yield result;
}
const extract = (start, end, str) => Array.from(
? matchAll(`(.+?)(${escapeRegex(start)}|${escapeRegex(end)}|$)`, str),
? ([, text, mark]) => ({
? ? marker: mark === end,
? ? value: text.trim()
? })
);
console.log(extract(
? "{startMarker}",
? "{endMarker}",
? "This is {startMarker} the string {endMarker} for {startMarker} example. {endMarker}"
));
添加回答
舉報(bào)