我正在处理一个平面文件,数据是逐行格式的,像这样
... blah blah blah | sku: 01234567 | price: 150 | ... blah blah blah
我想提取 sku 字段,它是 8 字符长的数字。但是,我不确定是否应该使用拆分或正则表达式,我不太擅长在 python 中使用正则表达式。
假设您的sku
值始终为 8 个字符长,并且始终以“sku”开头,并且可能还有一些“:”(中间有或没有空格),那么我将使用正则表达式r'sku[\s:]*(\d{8})'
::
>>> import re
>>> string = '... | sku: 01234567 | price: 150 | ... '
>>> re.findall(r'sku[\s:]*(\d{8})', string)[0]
'01234533'
如果您的sku
值长度可能是可变的,只需使用r'sku[\s:]*(\d*)'
:
>>> import re
>>> string = '... | sku: 01234 | price: 150 | sku: 99872453 | blah blah ... '
>>> re.findall(r'sku[\s:]*(\d*)', string)[0]
'01234'
>>> re.findall(r'sku[\s:]*(\d*)', string)[1]
'99872453'
编辑
如果你的 'sku' 后面跟着一些其他字符,比如sku1
, sku2
, sku-sp
, sku-18
or sku_anything
,你可以试试:
>>> re.findall(r'sku\D*(\d*)', string)[0]
这完全等同于:
>>> re.findall(r'sku[^0-9]*([0-9]*)', string)[0]
这是非常普遍的。它将匹配以 开头的任何内容sku
,然后是任何未确定数量的非十进制字符(\D*
或[^0-9]*
),以及一些十进制字符(\d*
或[0-9]*
)。它将返回后者(一串长度不确定的十进制字符)。
现在,我用来构建这些表达式的东西是什么意思:
*
:当跟随单个字符或一类字符时,该符号表示该表达式将匹配其所跟随的任何未确定数量的字符或类(*
表示“0或一些”,+
表示“至少一个”,?
表示“0或1 ”)。{}
的使用方式与 the *
, the+
和 the ?
, ie 相同。他们跟随一个字符或一类字符。它们也是量词。如果你说c{4}
,它将匹配由恰好 4 个 'c' 组成的任何字符串。如果您说c{1,6}
它将匹配由 1 到 6 'c' 组成的任何字符串。[]
: 定义一类字符。[abc]
表示任何字符“a”、“b”或“c”。[a-z]
表示任何小写字母。[A-Z]
、任意大写字母、[a-zA-Z]
任意大小写字母、[0-9]任意十进制字符。如果你想用点或逗号匹配小数,加上加号、减号和“e”(例如,对于指数),只需说[0-9,\.+-e]
.^
内部 - 用[]
, 定义的意思是“倒置的类”,除了类之外的所有东西。然后,[^0-9]
表示除十进制字符之外的[^a-z]
任何内容,除小写字母之外的任何内容,等等。这些是在 python 中预定义的类,用于使正则表达式语法更友好:
\s
: 将匹配任何间距字符(空格、制表符等)\d
: 将匹配任何十进制字符(0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ...这相当于[0-9]
,这是在正则表达式中表示字符类的另一种方式)\D
: 将匹配任何非十进制字符...这等效于[^0-9]
,这是在正则表达式中表达排除的字符类的另一种方式。\S
: 将匹配任何非空格字符...\w
: 将匹配任何“单词字符”\W
: 将匹配任何非单词字符()
定义了一些组。它们有很多用途。在这里,在 中findall
,该组突出显示您希望表达式返回的内容 ... 即。(\d{8})
或[0-9]{8}
表示您希望表达式仅返回匹配的完整字符串中的 8 个十进制字符的字符串。正则表达式真的很容易使用,而且非常有用。您只需要很好地了解他们可以做什么和他们不能做什么(它们仅限于常规语言。例如,如果您需要处理嵌套事物的级别,或者使用上下文无关语法定义的其他语言,那么正则表达式就赢了不够)。您可能希望查看以下页面:
像下面这样的东西应该可以满足您的需要,而不依赖于确切的间距和定位:
>>> s = '... blah blah blah | sku: 01234567 | price: 150 | ... blah blah blah'
>>> match_obj = re.search(r'sku\s*:\s*(\d+)', s)
>>> match_obj.group(1)
'01234567'
在您尝试使用该.group()
方法访问匹配对象之前,您应该检查是否实际发生了匹配,即:if match_obj: # do something with match
。
如果字符串中的所有 8 位数字都是 SKU 数字,则可以使用
re.findall(r"\b\d{8}\b", mystring)
\b
单词边界锚确保不会匹配较长数字/单词中的 8 位子字符串。
在我看来,您应该使用拆分、“sku:”和“|” 充当分隔符:
s = "blah blah blah | sku: 01234567 | price: 150 | ... blah blah blah"
s.split("sku:")[1].split("|")[0]
这是检查:
s = "blah blah blah | sku: 01234567 | price: 150 | ... blah blah blah"
s1 = s.split("sku:")
if len(s1) == 2:
print s1[1].split("|")[0]
如果所有管道分隔的字段也是(键:值),那么您最好保留其余数据,除非您需要它——您已经不得不解析字符串......
s = "sku: 01234567 | price: 150"
dict( k.split(':') for k in s.split('|') )
# {sku': ' 01234567 ', ' price': ' 150'}
可能想要修剪一些多余的前导空间