正则表达式:删除引号分隔字符串 [python] 之间的所有逗号
Regex : Remove all commas between a quote separated string [python]
什么是合适的正则表达式来删除字符串中的所有逗号:
12, 1425073747, "test", "1, 2, 3, ... "
结果:
12, 1425073747, "test", "1 2 3 ... "
我拥有的正确匹配的内容:
"((\d+), )+\d+"
但是,我显然不能用$1 $2来代替这个。我不能使用 "\d+, \d+" 因为它会匹配 12, 1425073747 这不是我想要的。如果有人可以解释如何递归解析值,那也将不胜感激。
这应该适合你:
>>> input = '12, 1425073747, "test", "1, 2, 3, ... "';
>>> print re.sub(r'(?!(([^"]*"){2})*[^"]*$),', "", input);
12, 1425073747, "test", "1 2 3 ... "
(?!(([^"]*"){2})*[^"]*$)
仅在 quotea 内匹配文本——避免匹配逗号后偶数个引号。
您可以使用带有简单 r'"[^"]*"'
正则表达式的 re.sub
并将匹配对象传递给用作替换参数的可调用对象,您可以在其中进一步操作匹配:
import re
text = '12, 1425073747, "test", "1, 2, 3, ... "'
print( re.sub(r'"[^"]*"', lambda x: x.group().replace(",", ""), text) )
参见Python demo。
如果引号之间的字符串可能包含转义引号,请使用
re.sub(r'(?s)"[^"\]*(?:\.[^"\]*)*"', lambda x: x.group().replace(",", ""), text)
这里,(?s)
是 re.S
/ re.DOTALL
标志的内联版本,其余是双引号字符串文字匹配模式。
奖金
- 删除双引号之间的所有空格:
re.sub(r'"[^"]*"', lambda x: ''.join(x.group().split()), text)
- 删除双引号内的所有非数字字符:
re.sub(r'"[^"]*"', lambda x: ''.join(c for c in x.group() if c.isdigit()), text)
- 删除双引号内的所有数字字符:
re.sub(r'"[^"]*"', lambda x: ''.join(c for c in x.group() if not c.isdigit()), text)
anubhava 提供的解决方案非常有用,事实上,这是我找到的唯一适用于指南的解决方案 - 这意味着真正可靠地删除了引用文本中的分号。然而,在一个 640 kB 的文本文件(是的,640)上使用它需要大约 3 分钟,这即使在老式的 i5 上也是不可接受的。
我的解决方案是实现一个 C++ 函数:
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
extern "C" // required when using C++ compiler
const char *
erasesemi(char *s)
{
bool WeAreIn = false;
long sl = strlen(s);
char *r = (char*) malloc(sl+1);
strcpy(r, s);
for (long i = 0; (i < (sl - 1)); i++)
{
if (s[i] == '"')
{
WeAreIn = not(WeAreIn);
}
if ((s[i] == ';') & WeAreIn)
{
r[i] = ',';
}
else
{
r[i] = s[i];
}
}
return r;
}
根据我在互联网上找到的,我使用了这个setup.py
from setuptools import setup, Extension
# Compile *mysum.cpp* into a shared library
setup(
# ...
ext_modules=[Extension('erasesemi', ['erasesemi.cpp'],), ],
)
之后你必须 运行
python3 setup.py build
主要代码中的相应行是:
import ctypes
import glob
libfile = glob.glob(
'build/lib.linux-x86_64-3.8/erasesemi.cpython-38-x86_64-linux-gnu.so')[0]
mylib = ctypes.CDLL(libfile)
mylib.erasesemi.restype = ctypes.c_char_p
mylib.erasesemi.argtypes = [ctypes.c_char_p]
..
data3 = mylib.erasesemi(str(data2).encode('latin-1'))
像这样,它在 < 1 秒内产生了预期的结果。最棘手的部分是找出如何将带有德语字符的字符串传递给 c++ 函数。当然,您可以使用任何您想要的编码。
什么是合适的正则表达式来删除字符串中的所有逗号:
12, 1425073747, "test", "1, 2, 3, ... "
结果:
12, 1425073747, "test", "1 2 3 ... "
我拥有的正确匹配的内容:
"((\d+), )+\d+"
但是,我显然不能用$1 $2来代替这个。我不能使用 "\d+, \d+" 因为它会匹配 12, 1425073747 这不是我想要的。如果有人可以解释如何递归解析值,那也将不胜感激。
这应该适合你:
>>> input = '12, 1425073747, "test", "1, 2, 3, ... "';
>>> print re.sub(r'(?!(([^"]*"){2})*[^"]*$),', "", input);
12, 1425073747, "test", "1 2 3 ... "
(?!(([^"]*"){2})*[^"]*$)
仅在 quotea 内匹配文本——避免匹配逗号后偶数个引号。
您可以使用带有简单 r'"[^"]*"'
正则表达式的 re.sub
并将匹配对象传递给用作替换参数的可调用对象,您可以在其中进一步操作匹配:
import re
text = '12, 1425073747, "test", "1, 2, 3, ... "'
print( re.sub(r'"[^"]*"', lambda x: x.group().replace(",", ""), text) )
参见Python demo。
如果引号之间的字符串可能包含转义引号,请使用
re.sub(r'(?s)"[^"\]*(?:\.[^"\]*)*"', lambda x: x.group().replace(",", ""), text)
这里,(?s)
是 re.S
/ re.DOTALL
标志的内联版本,其余是双引号字符串文字匹配模式。
奖金
- 删除双引号之间的所有空格:
re.sub(r'"[^"]*"', lambda x: ''.join(x.group().split()), text)
- 删除双引号内的所有非数字字符:
re.sub(r'"[^"]*"', lambda x: ''.join(c for c in x.group() if c.isdigit()), text)
- 删除双引号内的所有数字字符:
re.sub(r'"[^"]*"', lambda x: ''.join(c for c in x.group() if not c.isdigit()), text)
anubhava 提供的解决方案非常有用,事实上,这是我找到的唯一适用于指南的解决方案 - 这意味着真正可靠地删除了引用文本中的分号。然而,在一个 640 kB 的文本文件(是的,640)上使用它需要大约 3 分钟,这即使在老式的 i5 上也是不可接受的。
我的解决方案是实现一个 C++ 函数:
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
extern "C" // required when using C++ compiler
const char *
erasesemi(char *s)
{
bool WeAreIn = false;
long sl = strlen(s);
char *r = (char*) malloc(sl+1);
strcpy(r, s);
for (long i = 0; (i < (sl - 1)); i++)
{
if (s[i] == '"')
{
WeAreIn = not(WeAreIn);
}
if ((s[i] == ';') & WeAreIn)
{
r[i] = ',';
}
else
{
r[i] = s[i];
}
}
return r;
}
根据我在互联网上找到的,我使用了这个setup.py
from setuptools import setup, Extension
# Compile *mysum.cpp* into a shared library
setup(
# ...
ext_modules=[Extension('erasesemi', ['erasesemi.cpp'],), ],
)
之后你必须 运行
python3 setup.py build
主要代码中的相应行是:
import ctypes
import glob
libfile = glob.glob(
'build/lib.linux-x86_64-3.8/erasesemi.cpython-38-x86_64-linux-gnu.so')[0]
mylib = ctypes.CDLL(libfile)
mylib.erasesemi.restype = ctypes.c_char_p
mylib.erasesemi.argtypes = [ctypes.c_char_p]
..
data3 = mylib.erasesemi(str(data2).encode('latin-1'))
像这样,它在 < 1 秒内产生了预期的结果。最棘手的部分是找出如何将带有德语字符的字符串传递给 c++ 函数。当然,您可以使用任何您想要的编码。