如何使用正则表达式提取JSX标签中可能为多行的Prop值(以Story组件的title属性为例)
提取JSX中Story组件的title属性值
问题描述
我需要从以下JSX代码里提取<Story>组件的title属性值:
<Story title={'Disabled Text Input'}> <TextInput label="Disabled Text Input" disabled /> </Story> <Story title={'Disabled ways for Text Input to work'}> <TextInput label="Disabled Text Input" disabled {...someExtraProps}/> </Story>
想要的结果是:Disabled Text Input 和 Disabled ways for Text Input to work。
目前我已经用正则 <Story[^]+?>(?<component>[^$]*?)</Story>/g 拿到了Story的子组件,但提取title时卡壳了——这个属性写法太多了:
title={"some"}title="Some"title='Some'title={'Some'}
而且属性值还可能是多行的,求一个能覆盖这些场景的正则表达式方案。
解决方案
针对你遇到的多种title写法(不同引号、多行值),我整理了一个能精准匹配的正则表达式,还能处理大部分边缘场景:
<Story\s+[^>]*?title=(["'{])(?<title>(?:(?!\1)[\s\S])*?)\1[^>]*>
正则怎么工作的?
我拆解一下关键部分,方便你理解:
<Story\s+:匹配<Story标签开头,加\s+是为了避免误匹配类似<Storybook>这种带后缀的标签[^>]*?:非贪婪匹配标签里的其他内容,直到找到title=(这样不管title在属性列表的哪个位置都能匹配)(["'{]):捕获第一个引号(单双引号或反引号),记为分组1——后面用它来匹配对应的闭合引号,避免不同引号类型混淆(?<title>(?:(?!\1)[\s\S])*?):这是核心的命名捕获组title,[\s\S]能匹配包括换行在内的所有字符,(?!\1)是负向前瞻,确保不会提前碰到和分组1一样的闭合引号,非贪婪模式*?防止过度匹配\1:匹配和分组1相同的闭合引号,确保属性值完整[^>]*>:匹配标签剩下的内容直到标签闭合
在JavaScript中使用示例
给你写个实际能用的代码片段,直接就能提取所有title:
const jsxContent = ` <Story title={'Disabled Text Input'}> <TextInput label="Disabled Text Input" disabled /> </Story> <Story title="Disabled ways for Text Input to work"> <TextInput label="Disabled Text Input" disabled {...someExtraProps}/> </Story> <Story title='Multi-line Title Example'> <TextInput label="Test" /> </Story> <Story title={"Dynamic " + "Title"}> <TextInput /> </Story> `; const titleRegex = /<Story\s+[^>]*?title=(["'{])(?<title>(?:(?!\1)[\s\S])*?)\1[^>]*>/g; const extractedTitles = []; let matchResult; while ((matchResult = titleRegex.exec(jsxContent)) !== null) { // 可选trim,去掉属性值首尾的空白 extractedTitles.push(matchResult.groups.title.trim()); } console.log(extractedTitles); // 输出: ["Disabled Text Input", "Disabled ways for Text Input to work", "Multi-line\nTitle Example", "Dynamic " + "Title"]
额外说明
- 如果你的
title属性值里有转义引号(比如title="He said \"Hello\""),可以把正则调整成下面这样,就能匹配转义后的引号了:<Story\s+[^>]*?title=(["'{])(?<title>(?:\\\1|(?!\1)[\s\S])*?)\1[^>]*> - 正则解析JSX毕竟是“hack”方案,如果你的场景涉及非常复杂的JSX(比如嵌套表达式、注释混在属性里),更推荐用专门的JSX解析库(比如
@babel/parser)来生成AST,再从AST里提取属性值,这样更可靠。
内容的提问来源于stack exchange,提问作者Shujath
相关产品推荐
相关产品推荐

