-
Notifications
You must be signed in to change notification settings - Fork 201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: 导出 CSV 时特殊处理逗号等字符 #3091
fix: 导出 CSV 时特殊处理逗号等字符 #3091
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import { map } from 'lodash'; | ||
import { | ||
AsyncRenderThreshold, | ||
CSV_SEPARATOR, | ||
TAB_SEPARATOR, | ||
type DataItem, | ||
type Formatter, | ||
|
@@ -14,7 +16,11 @@ import type { | |
import { CopyMIMEType } from '../../../common/interface/export'; | ||
import { Node } from '../../../facet/layout/node'; | ||
import type { SpreadSheet } from '../../../sheet-type'; | ||
import { getHeaderList, getHeaderMeasureFieldNames } from '../method'; | ||
import { | ||
escapeCSVField, | ||
getHeaderList, | ||
getHeaderMeasureFieldNames, | ||
} from '../method'; | ||
import { unifyConfig } from './common'; | ||
|
||
export abstract class BaseDataCellCopy { | ||
|
@@ -50,8 +56,14 @@ export abstract class BaseDataCellCopy { | |
dataMatrix: SimpleData[][], | ||
separator: string, | ||
): CopyablePlain { | ||
let escapeDataMatrix: SimpleData[][] = dataMatrix; | ||
|
||
if (separator === CSV_SEPARATOR) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 考虑下是否去掉 |
||
escapeDataMatrix = map(dataMatrix, (row) => map(row, escapeCSVField)); | ||
} | ||
|
||
return this.config.transformers[CopyMIMEType.PLAIN]( | ||
dataMatrix, | ||
escapeDataMatrix, | ||
separator, | ||
) as CopyablePlain; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,6 +66,30 @@ export const trimTabSeparator = (text: string) => { | |
return replace(text, new RegExp(TAB_SEPARATOR, 'g'), ''); | ||
}; | ||
|
||
/** | ||
* https://en.wikipedia.org/wiki/Comma-separated_values#Example | ||
* 根据 CSV 规范,按以下规则处理字段内容: | ||
* 若字段包含 ,、"、\n 或 \t → 用双引号包裹字段。 | ||
* 若字段中的双引号 → 转义为两个双引号 ""。 | ||
* @param field | ||
*/ | ||
export const escapeCSVField = (field: SimpleData): SimpleData => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 建议和 trimTabSeparator 统一下, trimTabSeparator 去掉,然后 escapeCSVField => escapeField |
||
if (typeof field !== 'string') { | ||
return field; | ||
} | ||
|
||
// 检查是否需要转义:包含逗号、双引号或换行符 | ||
if (/[",\n\t]/.test(field)) { | ||
// 转义双引号 -> 两个双引号 | ||
field = field.replace(/"/g, '""'); | ||
|
||
// 用双引号包裹字段 | ||
return `"${field}"`; | ||
} | ||
|
||
return field; | ||
}; | ||
|
||
export const getHeaderMeasureFieldNames = ( | ||
fields: string[], | ||
spreadsheet: SpreadSheet, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为啥要额外定义一次