在python中从字符串中提取罗马数字

2024-09-27 21:34:26 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个字符串列表,包含用拉丁数字表示的和弦,如下所示:

['ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7', 'ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7']

我想把这些字符串分成3个子列表,如下所示:

numerals = ['ii', 'vi', 'V', 'IV', 'I', 'V', 'IV', 'ii', 'vi', 'V', 'IV', 'I', 'V', 'IV']
chord_type=['min', 'min', 'maj', 'maj', 'maj', 'maj','maj', 'min', 'min', 'maj', 'maj', 'maj', 'maj','maj']
extentions=['7','7','', 'add9','add9','','7','7','7','','add9','add9','','7']

(如您所见,大写罗马数字对应于和弦类型中的“maj”,非大写字母对应于“min”。)

在我的例子中,所有可能的罗马数字:

i, ii, iii, iv, v, vi, vii, I, II, III, IV, V, VI, VII

注意,我们不需要MCLX

我知道我可以从Python中的字符串中提取或拆分数字,如here所述,但如何提取罗马数字呢

我曾想过使用类似于matchregex的东西,但我对如何定义这7个罗马数字感到困惑,因为这些字符可能会再次出现在字符串中


Tags: 字符串列表数字miniivimaj罗马数字
3条回答

使用.startswithstring方法可以非常简单地做到这一点,如下所示:

nummerals = ['i', 'ii', 'iii', 'iv', 'v', 'vi', 'vii', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
lst = ['ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7', 'ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7']


nummerals.sort(key=len, reverse=True)  # see note 1

res = [next(n for n in nummerals if y.startswith(n)) for y in lst]  # see note 2
print(res)  # -> ['ii', 'vi', 'V', 'IV', 'I', 'V', 'IV', 'ii', 'vi', 'V', 'IV', 'I', 'V', 'IV']

注释

  1. 原始的nummerals列表必须按长度排序(降序),以确保您匹配可能的最大数值(.startswithfor 'ii7'将同时匹配'i''ii',但您需要第二个)
  2. 上面的代码可能抛出StopIteration错误。如果要防止这种情况发生,请向next提供一个回退值

若罗马数字总是在第一位,那个么你们可以这样做

import re
chords = ['ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7', 'ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7']
numerals = [re.match('[IiVv]+', i).group(0) for i in chords]
print(numerals)

输出

['ii', 'vi', 'V', 'IV', 'I', 'V', 'IV', 'ii', 'vi', 'V', 'IV', 'I', 'V', 'IV']

请注意,我使用了re.match,因为它是尝试将字符串开头的模式和有限的数字应用于示例中的现有数字(而不是使用所有已知的,即^{

我的解决方案使用了一个有点复杂的正则表达式,它有两个优点:

  1. 如果一个数的扩展看起来是一个不可能的罗马数字的一部分,例如^ {CD1> },然后^ {< CD2> },天真的方法会考虑数字{{CD3}},而我的方法只考虑^ {CD1}},以{{CD2}}作为扩展。<李>
  2. 如果您需要用更大的数字扩展应用程序,这将适用于非常大的数字

编辑:显然,对于和弦来说,数字越大可能没用,但谁知道呢?也许你会更新音乐的工作方式🎵

我使用的正则表达式来自here。我对它做了一点修改,使它在这里工作

import re

l = ['ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7', 'ii7', 'vi7', 'V', 'IVadd9', 'Iadd9', 'V', 'IVmaj7']

numerals = []
chord_type = []
extensions = []

roman_regex = '^M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})'

for e in l:
    roman_search = re.search(roman_regex , e.upper())
    start = roman_search.start()
    end = roman_search.end()
    roman = e[start:end]

    numerals.append(roman)
    chord_type.append('maj' if roman[0].upper() == roman[0] else 'min')
    extensions.append(e[end:])
>>> print(numerals)
... print(chord_type)
... print(extensions)

['ii', 'vi', 'V', 'IV', 'I', 'V', 'IV', 'ii', 'vi', 'V', 'IV', 'I', 'V', 'IV']
['min', 'min', 'maj', 'maj', 'maj', 'maj', 'maj', 'min', 'min', 'maj', 'maj', 'maj', 'maj', 'maj']
['7', '7', '', 'add9', 'add9', '', 'maj7', '7', '7', '', 'add9', 'add9', '', 'maj7']

相关问题 更多 >

    热门问题