2

我正在处理一个平面文件,数据是逐行格式的,像这样

... blah blah blah | sku: 01234567 | price: 150 | ... blah blah blah

我想提取 sku 字段,它是 8 字符长的数字。但是,我不确定是否应该使用拆分或正则表达式,我不太擅长在 python 中使用正则表达式。

4

5 回答 5

3

假设您的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-18or 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+和 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 个十进制字符的字符串。

正则表达式真的很容易使用,而且非常有用。您只需要很好地了解他们可以做什么和他们不能做什么(它们仅限于常规语言。例如,如果您需要处理嵌套事物的级别,或者使用上下文无关语法定义的其他语言,那么正则表达式就赢了不够)。您可能希望查看以下页面:

于 2012-06-20T18:13:07.970 回答
1

像下面这样的东西应该可以满足您的需要,而不依赖于确切的间距和定位:

>>> 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

于 2012-06-20T18:15:20.400 回答
0

如果字符串中的所有 8 位数字都是 SKU 数字,则可以使用

re.findall(r"\b\d{8}\b", mystring)

\b单词边界锚确保不会匹配较长数字/单词中的 8 位子字符串。

于 2012-06-20T18:01:45.337 回答
0

在我看来,您应该使用拆分、“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]
于 2012-06-20T18:05:12.593 回答
0

如果所有管道分隔的字段也是(键:值),那么您最好保留其余数据,除非您需要它——您已经不得不解析字符串......

s = "sku: 01234567 | price: 150"
dict( k.split(':') for k in s.split('|') )
# {sku': ' 01234567 ', ' price': ' 150'}

可能想要修剪一些多余的前导空间

于 2012-06-20T18:14:15.457 回答