活动介绍

19、已知字符串:“this is a test of python”. 用正则表达式编写并添加注释: (1)统计该字符串中字母s出现的次数 (2)取出子字符串"test" (3)将字符串中每个单词的第一个字母变成大写, 输出到显示器。 (4)用两种方式实现该字符串的倒叙输出

时间: 2025-01-25 16:12:08 浏览: 41
好的,以下是使用Python编写的正则表达式示例,并附有详细注释: ```python import re # 原始字符串 text = "this is a test of python" # (1)统计该字符串中字母s出现的次数 s_count = len(re.findall(r's', text)) print(f"字母s出现的次数: {s_count}") # (2)取出子字符串"test" test_substring = re.search(r'test', text).group() print(f"子字符串 'test': {test_substring}") # (3)将字符串中每个单词的第一个字母变成大写,输出到显示器 capitalized_text = ' '.join([word.capitalize() for word in text.split()]) print(f"每个单词首字母大写: {capitalized_text}") # (4)用两种方式实现该字符串的倒叙输出 # 方法一:使用切片 reversed_text_slice = text[::-1] print(f"倒序输出(切片): {reversed_text_slice}") # 方法二:使用reversed函数 reversed_text_reversed = ''.join(reversed(text)) print(f"倒序输出(reversed): {reversed_text_reversed}") ```
相关问题

已知字符串:“this is a test of python”. 用正则表达式编写并添加注释: 将字符串中每个单词的第一个字母变成大写

好的,我来为您编写一个Python正则表达式,用于将字符串中每个单词的第一个字母变成大写,并添加详细的注释: ```python import re # 原始字符串 text = "this is a test of python" # 使用正则表达式进行替换 # 解释: # (^|\s) - 匹配字符串开头或空白字符 # (\w) - 捕获组,匹配一个字母或数字字符 # (\w*) - 捕获组,匹配零个或多个字母或数字字符 # 整个模式匹配每个单词的第一个字母 pattern = r'(^|\s)(\w)(\w*)' # 替换函数 # 参数: # match - 匹配对象 def capitalize_first_letter(match): # 获取匹配的空白字符或字符串开头 prefix = match.group(1) # 获取单词的第一个字母 first_letter = match.group(2).upper() # 获取单词的剩余部分 rest_of_word = match.group(3) # 返回修改后的单词 return prefix + first_letter + rest_of_word # 使用re.sub()进行替换 # re.IGNORECASE - 忽略大小写 # re.MULTILINE - 多行模式 result = re.sub(pattern, capitalize_first_letter, text, flags=re.IGNORECASE) # 输出结果 print(result) ``` 这段代码的工作原理如下: 1. 我们定义了一个原始字符串 `text`。 2. 我们创建了一个正则表达式模式 `pattern`,用于匹配每个单词的第一个字母。 3. 我们定义了一个替换函数 `capitalize_first_letter`,用于将匹配的字母转换为大写。 4. 我们使用 `re.sub()` 函数应用这个正则表达式和替换函数。 5. 最后,我们打印结果。 这个正则表达式的优点是它会保留原始的空白字符和大小写,这使得它在处理更复杂的文本时更加灵活。

python 正则匹配获得sql表名

<think>我们面对的任务是从SQL查询语句中提取表名。根据用户需求,我们需要使用Python的正则表达式来实现。考虑到SQL语句的多样性,表名可能出现在不同的上下文中。例如:1.简单的SELECT语句:SELECT*FROMtable_name2.带有模式(schema)的表名:SELECT*FROMschema.table_name3.使用方括号或引号引起来的表名(常见于SQLServer等):SELECT*FROM[schema].[table_name]或SELECT*FROM"schema"."table_name"4.多表连接:SELECT*FROMtable1,table2或SELECT*FROMtable1JOINtable25.子查询:这种情况可能比较复杂,我们可能暂时不考虑子查询中的表(因为子查询中的表可能是临时表或者别名)我们的目标是提取FROM关键字后面以及JOIN关键字后面的表名。但是,请注意,SQL语句可能非常复杂,包括子查询、嵌套查询等,而正则表达式处理嵌套结构是有局限的。因此,我们这里主要考虑相对简单的SQL语句,或者至少是FROM子句和JOIN子句相对直接的情况。根据引用[3]中的例子,我们可以观察到表名可能以多种形式出现:-Config-[dbo].IMEIUser-dbo.LotteryLog-[GreenPrize]-[dbo].[Config]-dbo.[Prize]-[DBName].[dbo].[Config]我们设计正则表达式的思路:1.匹配FROM或JOIN关键字(注意:JOIN可能有多种,如INNERJOIN,LEFTJOIN等,所以我们匹配关键字后面跟着的JOIN)2.匹配关键字后面的表名部分。表名部分可能由以下组成:-可选的数据库名和模式名(用点分隔),每个部分都可以用方括号或引号括起来,也可以不用。-表名本身也可以用方括号或引号括起来,或者直接是标识符。标识符的规则:通常由字母、数字、下划线等组成,但有时也会包含其他字符(如空格),所以当包含空格或特殊字符时,通常会用方括号或引号括起来。我们可以尝试分步匹配,但为了简化,我们可以设计一个匹配表名(包括可能的限定符)的正则表达式。一个表名(包括可能的数据库名、模式名)的组成部分可以这样匹配:(?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*解释:第一部分:一个标识符,可以是:\[[^\]]+\]:匹配方括号内的任何非右方括号字符|\"[^\"]+\":或者双引号内的任何非双引号字符|\w+:或者一个或多个单词字符(字母、数字、下划线)后面可以跟零个或多个:点号分隔的另一个标识符(同样可以是方括号、引号或单词字符)然后,我们需要匹配FROM或JOIN关键字后面的这个表名模式。注意,关键字后面可能有空格,表名后面可能有空格或逗号等。但是,我们也要注意避免匹配到子查询中的FROM或JOIN。这比较困难,所以我们假设用户提供的SQL语句中,最外层的FROM和JOIN是我们关心的。另外,我们可能还需要考虑表别名,例如:FROMtable1ASt1,但我们只需要表名,所以别名可以忽略。同样,我们也要忽略掉ON等条件子句。因此,我们可以这样写正则表达式:(?:FROM|JOIN)\s+((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*)但是,这个表达式会匹配整个限定名(如db.schema.table)。但是,我们可能只需要表名部分?或者保留完整路径?根据需求,我们可以选择保留完整路径或者只取最后一部分。另外,注意这个表达式会匹配到JOIN前面的类型(如INNERJOIN),所以我们可能需要匹配各种JOIN:(?:FROM|(?:INNER\s+)?JOIN|LEFT\s+JOIN|RIGHT\s+JOIN|FULL\s+JOIN)\s+但是,这样写会很长。我们可以简化:因为所有JOIN前面都有关键字JOIN,所以我们匹配:\b(?:FROM|JOIN)\b但是,这样会漏掉LEFTJOIN等,所以我们改为:\b(?:FROM|(?:INNER\s+)?JOIN|LEFT\s+OUTER?\s+JOIN|RIGHT\s+OUTER?\s+JOIN|FULL\s+OUTER?\s+JOIN|CROSS\s+JOIN)\b这样写比较全面,但可能过于复杂。另一种思路是:我们匹配FROM和任何以JOIN结尾的关键字(但注意FROM不是以JOIN结尾)。我们可以拆分成两部分:先匹配FROM,然后匹配各种JOIN关键字。但是,为了简单,我们这里先考虑匹配FROM和JOIN(包括前面的修饰符)作为关键字。实际上,我们可以先提取FROM和JOIN后面的表名,而不考虑JOIN的类型,因为表名总是在这些关键字后面。因此,我们可以这样:\b(?:FROM|(?:[A-Z]+\s+)*JOIN)\s+解释:匹配FROM或者任何前面可能有大写单词(如INNER,LEFT等)后面跟着JOIN的关键字。注意:这个正则可能会匹配到一些不是关键字的地方,但考虑到SQL语句通常是大写,或者我们可以用re.IGNORECASE标志忽略大小写。另外,注意表名后面可能有别名,比如:FROMtable1t1,或者JOINtable2ASt2。我们需要跳过别名。别名通常是一个单词(或带引号/方括号的标识符),并且前面可能有AS关键字。因此,在匹配表名后,我们可能会遇到:-空格然后一个单词(别名)-或者逗号(表示下一个表)-或者ON关键字(开始连接条件)-或者WHERE等我们不需要匹配别名,所以我们在匹配表名后,应该忽略后面的别名部分。因此,我们可以调整:在匹配表名后,如果后面跟着AS或一个标识符(别名),我们就不捕获这个别名。所以,整个正则表达式可以设计为:\b(?:FROM|(?:[A-Z]+\s+)*JOIN)\s+((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*)\s*(?:AS\s+\w+|\s+\w+)?(?=\s+|,|$|ON)解释:-\b(?:FROM|(?:[A-Z]+\s+)*JOIN)\s+:匹配关键字(FROM或各种JOIN)后面至少一个空格-((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*):捕获组1,匹配表名(可能带限定符)-\s*(?:AS\s+\w+|\s+\w+)?:匹配可选的别名(可能有AS,也可能没有)-(?=\s+|,|$|ON):正向先行断言,确保后面是空格、逗号、结束或者ON关键字(这样确保我们不会匹配过多)但是,这个正则表达式仍然可能不够健壮,因为SQL语句的复杂性。另外,我们还需要注意,同一个SQL语句中可能有多个表(例如逗号分隔的多表),所以我们需要匹配多个表。对于逗号分隔的情况,例如:FROMtable1,table2,table3我们的正则表达式在匹配完table1后,由于逗号不在我们表名后面的断言中(我们断言了逗号),所以下一次匹配可以从逗号后面的table2开始?但是,我们的关键字只匹配FROM和JOIN,所以逗号后面的表不会被匹配到。因此,我们需要特别处理逗号分隔的情况。我们可以修改正则表达式,在FROM后面匹配多个表(逗号分隔)。但是,这会使正则表达式变得复杂。另一种思路:我们分两步:第一步:定位FROM子句(直到遇到WHERE、GROUPBY等关键字或结束)第二步:在这个子句中提取表名(包括JOIN子句)但是,为了简单起见,我们这里先处理每个表都由FROM或JOIN引入的情况(包括逗号分隔的情况,我们可以通过多次匹配,但注意逗号分隔的表前面没有关键字)。所以,我们调整:在FROM关键字后面,我们可能匹配多个表(用逗号分隔),那么我们可以把逗号后面的表看作是隐式的JOIN?所以我们可以这样:(?:FROM|JOIN|,)\s+((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*)\s*(?:AS\s+\w+|\s+\w+)?(?=\s+|,|$|ON)这里,我们在关键字列表中加入逗号。这样,逗号后面跟着的表名也会被匹配。但是,注意逗号可能出现在SELECT子句中,所以这样可能会误匹配。因此,我们可能需要限制:逗号匹配只发生在FROM子句中。由于复杂性,我们这里采用一种折中:先匹配FROM和JOIN关键字后面的表名,然后单独处理逗号分隔的情况。我们可以先通过正则找到FROM子句的范围,然后在这个范围内提取逗号分隔的表。但是,为了快速实现,我们假设用户提供的SQL语句中,表名都是由FROM或JOIN引入的(即不使用逗号分隔的旧式连接)。如果用户使用逗号分隔,那么只有第一个表前面有FROM,后面的表前面是逗号,所以我们还是需要匹配逗号。因此,我们决定使用:\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s+((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*)\s*(?:AS\s+\w+|\s+\w+)?(?=\s+|,|$|ON)注意:这个正则表达式可能会匹配到SELECT子句中的逗号(如果逗号后面跟着一个空格和一个标识符,而这个标识符又符合表名的模式,就可能被误认为表名)。因此,我们最好先定位FROM子句。考虑到时间,我们采用一个相对简单的方法:我们只考虑在FROM关键字出现之后,且在后续关键字(如WHERE、GROUPBY、HAVING、ORDERBY、LIMIT等)之前的字符串中提取表名。步骤:1.使用正则表达式定位FROM子句的范围:从FROM开始,直到遇到WHERE等关键字或语句结束。2.在这个范围内,使用正则表达式提取表名(包括JOIN和逗号后面的表名)。但是,这样处理仍然复杂,因为子查询的存在可能会干扰。鉴于问题的复杂性,我们这里先实现一个基础版本,它可能无法处理所有情况,但对于大多数简单查询有效。我们最终的正则表达式(不考虑子查询,只匹配显式的FROM、JOIN和逗号):pattern=r'\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s*((?:\[[^\]]+\]|\"[^\"]+\"|\w+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|\w+))*)'然后,我们使用re.IGNORECASE标志。但是,我们还没有处理别名:别名部分我们不想捕获,所以我们在捕获组中只包含表名部分,而别名部分不包含在捕获组中。另外,注意表名前后可能有空格,我们在捕获后可以去掉空格。我们写一个Python函数来实现:步骤:1.使用re.findall()匹配整个SQL语句,找出所有符合模式的部分。2.返回捕获组1(即表名)的列表。但是,我们可能会匹配到重复的表名,或者同一个表多次出现(例如自连接),这取决于需求,我们可能要去重,但用户没有要求,我们先返回所有出现的表名。另外,注意我们匹配到的表名可能是带模式或数据库名的完整名称,用户可能需要拆分,但需求只是提取表名,所以我们返回完整名称。我们测试几个例子(基于引用[3]中的例子)。例如:sql1="SELECT*FROMConfig"sql2="SELECT*FROM[dbo].IMEIUser"sql3="SELECT*FROMdbo.LotteryLog"sql4="SELECT*FROM[GreenPrize]"sql5="SELECT*FROM[dbo].[Config]"sql6="SELECT*FROMdbo.[Prize]"sql7="SELECT*FROM[DBName].[dbo].[Config]"sql8="SELECT*FROMtable1,table2"sql9="SELECT*FROMtable1INNERJOINtable2ONtable1.id=table2.id"注意:在sql8中,我们希望提取table1和table2。另外,注意子查询的情况(我们暂时不处理):sql10="SELECT*FROM(SELECT*FROMtemp)ASt"在sql10中,我们不应该提取temp(因为它在子查询中),但是我们的正则表达式可能会匹配到子查询中的FROM。所以我们需要避免。如何避免?我们可以尝试跳过括号内的内容。但是,正则表达式处理嵌套括号很困难。因此,我们这里先不考虑子查询,如果用户有需求,我们可以建议使用SQL解析器(如sqlparse)而不是正则表达式。现在,我们编写代码。另外,注意我们的正则表达式可能会匹配到字符串常量中的内容,例如:"SELECT*FROMtable1WHEREcomment='FROMtable2'"这里,'FROMtable2'是一个字符串,不应该被匹配。因此,我们最好先去掉字符串常量。但同样,这会使问题复杂化。因此,我们明确这个正则表达式适用于简单的SQL语句,不包含子查询和字符串常量中的类似模式。代码实现:importredefextract_table_names(sql):#正则表达式模式#注意:我们使用re.IGNORECASE忽略关键字大小写pattern=r'\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s*((?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+))*)'#解释:我们修改了表名部分,因为原来的\w+不能匹配包含点号的表名(实际上表名不应该包含点号,但限定名是多个部分用点连接)#但是,我们上面的模式已经可以匹配多个点连接的限定名。但是,我们修改了非限定符部分:原来用\w+,现在用[^\s\.,;()]+,表示除了空格、点、逗号、分号、括号以外的字符。#为什么这样改?因为原来的\w+不能匹配包含其他字符(如连字符)的表名,而用引号或方括号括起来的表名我们已经单独匹配了。#但是,对于没有引号或方括号的表名,我们允许非空白、非点、非逗号等字符。注意,表名也可能包含下划线、数字等,所以用[^\s\.,;()]是合理的。#但是,这个模式可能会匹配到其他东西,比如函数名,但这里我们假设在FROM/JOIN/,后面的就是我们想要的。matches=re.findall(pattern,sql,re.IGNORECASE)#返回去重后的列表(但保留顺序,因为同一个表出现多次可能是重复,但用户可能想知道多次出现)#用户需求是提取表名,所以返回所有提取到的表名(包括重复)returnmatches测试上面的例子。但是,注意在sql2中,我们提取到的是"[dbo].IMEIUser",这是一个整体。用户可能需要分别获得每个部分?但我们需求是提取表名,所以整个作为表名?或者,通常我们认为最后一部分是表名。但用户没有要求,我们返回完整名称。另外,在sql5中,我们提取到的是"[dbo].[Config]",同样是一个整体。如果用户希望只取表名部分(即最后一个标识符),我们可以对每个匹配结果进行拆分,取最后一个点之后的部分(并去掉方括号或引号)。但这不是当前需求,所以先返回完整名称。我们测试一下:对于sql1:"SELECT*FROMConfig"->返回['Config']对于sql2:"SELECT*FROM[dbo].IMEIUser"->返回['[dbo].IMEIUser'],但实际上我们可能希望得到IMEIUser(表名)和dbo(模式名)。但需求是提取表名,这个整体就是表名的限定名。如果用户只需要表名(不带模式),我们可以再处理:defextract_table_names(sql,only_table_name=False):#...先得到匹配的列表ifonly_table_name:result=[]fornameinmatches:#将整个限定名按点分割,取最后一部分parts=re.split(r'\s*\.\s*',name)last_part=parts[-1]#去掉方括号或引号iflast_part.startswith('[')andlast_part.endswith(']'):last_part=last_part[1:-1]eliflast_part.startswith('"')andlast_part.endswith('"'):last_part=last_part[1:-1]result.append(last_part)returnresultelse:returnmatches但我们先不实现这个,因为需求没有明确。现在,我们根据上面的例子测试。注意:在sql8:"SELECT*FROMtable1,table2"应该返回['table1','table2']。但是,我们的正则表达式在匹配','的时候,注意模式中有一个逗号,所以匹配','时,后面的空格和table2会被捕获。但是,我们的模式中,关键字后面有\s*,所以逗号后面的空格会被跳过。但是,在sql8中:首先匹配FROM,然后空格,然后table1->第一个匹配是'table1'然后,逗号后面的空格,然后table2->第二个匹配是'table2'所以,应该可以匹配到两个。测试sql9:"SELECT*FROMtable1INNERJOINtable2ON..."->应该匹配到table1(由FROM引入)和table2(由JOIN引入)。但是,注意在FROM和table1之间有一个空格,然后INNERJOIN后面也有空格,所以可以匹配到。但是,我们的正则表达式在FROM和JOIN之间没有匹配,所以只匹配FROM后面的table1和JOIN后面的table2。所以,我们编写代码并测试。另外,注意别名问题:我们之前的设计中,在表名后面有别名,我们用非捕获组跳过了别名。但是,在正则表达式中,我们并没有在捕获组后面加入别名的匹配,因为我们发现别名可能干扰表名的匹配(如果别名和表名写在一起,我们可能会捕获整个表名和别名)。所以我们在上面模式中,在捕获组后面加入了别名的匹配(但是非捕获的),并且使用正向先行断言确保后面是空格等。但是,在findall中,我们只返回捕获组1,所以别名不会被返回。但是,我们上面的模式中并没有加入别名的匹配(我们之前设计了一个带别名的模式,但后来简化了)。为了简单,我们暂时不考虑别名,因为别名不影响表名的提取(表名在别名前面)。因此,我们使用上面的简化模式(没有别名匹配部分)也能提取表名,因为别名在表名之后,而我们匹配表名后,别名不在捕获组中。但是,如果表名后面紧跟别名(没有空格),例如:FROMtable1t1,那么我们的模式会匹配到"table1t1"吗?不会,因为我们的表名模式是:非空格、逗号、点等字符组成的序列,所以table1匹配后,空格后面的t1不会被包含在捕获组中。所以,我们使用上面的模式。但是,我们修改一下:在表名模式中,我们允许的字符集是[^\s\.,;()],所以表名内部不能有空格。因此,表名后面如果有空格,那么空格后面的别名就不会被包含。所以,我们不需要特别处理别名。开始写代码,并测试。注意:我们还需要考虑SQL语句中可能有注释,注释中的FROM/JOIN也会被匹配。因此,理想情况下,我们应该去掉注释。但这里为了简单,先不考虑。我们写一个函数,然后测试。另外,注意分号:SQL语句可能以分号结束,所以我们在匹配时,表名后面可能遇到分号(作为结束),所以我们在正向先行断言中加入分号。修改模式:pattern=r'\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s*((?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+))*)(?=\s+|\s*,|\s*;|$|ON)'这个模式在表名后面要求遇到空格、逗号(前面可能有空格)、分号(前面可能有空格)、结束或ON。但是,这样写比较复杂。我们可以用:pattern=r'\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s*((?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+))*)\s*(?=[,;]|\s+ON\b|\s+WHERE\b|\s+GROUP\b|\s+HAVING\b|\s+ORDER\b|\s+LIMIT\b|$)'这样,我们使用了一个更复杂的先行断言,确保表名后面是逗号、分号、ON等关键字或结束。但是,这样写关键字列表很长,而且不同数据库的关键字可能不同。因此,我们回到简单的思路:匹配表名部分(由我们定义的标识符组成),然后交给后续处理去重和清理。我们使用最初的正则表达式,然后从匹配结果中去掉可能包含的别名(通过空格分割,取第一个部分?不行,因为表名可能有空格(如果有引号或方括号))。所以,我们坚持使用:pattern=r'\b(?:FROM|(?:[A-Z]+\s+)*JOIN|,)\s*((?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+)(?:\s*\.\s*(?:\[[^\]]+\]|\"[^\"]+\"|[^\s\.,;()]+))*)'然后,我们提取后,再对每个匹配的表名进行处理:如果表名中有AS关键字,那么我们需要去掉AS后面的部分。但这样很麻烦。因此,我们暂时不处理别名,假设用户提供的SQL语句中表名后面没有紧跟别名(或者即使有别名,我们提取的表名部分也是正确的,因为别名不在我们的捕获组中)。我们编写代码并测试。测试用例:sql1="SELECT*FROMConfig"->['Config']sql2="SELECT*FROM[dbo].IMEIUser"->['[dbo].IMEIUser']sql8="SELECT*FROMtable1,table2"->['table1','table2']sql9="SELECT*FROMtable1INNERJOINtable2ONtable1.id=table2.id"->['table1','table2']另外,测试有别名的情况:sql11="SELECT*FROMtable1ASt1"->应该返回['table1'],因为别名不在捕获组中。sql12="SELECT*FROMtable1t1"->同样返回['table1']但是,注意:如果表名和别名之间没有空格?例如:FROMtable1t1,那么table1t1会被当作表名。但这种情况很少,因为表名和别名通常有空格。所以,我们按照上述实现。代码:</think>### 使用 Python 正则表达式提取 SQL 表名 以下是使用 Python 正则表达式从 SQL 查询中提取表名的完整解决方案: ```python import re def extract_table_names(sql): """ 从 SQL 查询中提取表名(支持带/不带方括号的格式) 参数: sql (str): SQL 查询字符串 返回: list: 提取到的表名列表 """ # 核心正则表达式(忽略大小写) pattern = r""" (?: # 非捕获组:匹配关键字 FROM\s+ # FROM 关键字 | JOIN\s+ # JOIN 关键字 | ,\s* # 逗号分隔的表 ) (?: # 非捕获组:表名前缀(数据库/架构名) (?: \[?\w+\]? # 带或不带方括号的标识符 \s*\.\s* # 点分隔符 )* # 0个或多个前缀 ) ( # 捕获组1:表名主体 (?: \[[^\]]+\] # 带方括号的表名 | [^\s\.,;()]+ # 不带方括号的表名(排除特殊字符) ) ) (?=\s|,|;|$) # 正向先行断言:确保表名后是空格/逗号/结束符 """ matches = re.findall(pattern, sql, re.VERBOSE | re.IGNORECASE) return [re.sub(r'^\[|\]$', '', name) for name in matches] # 去除方括号 # 测试用例 test_sqls = [ "SELECT * FROM Config", "SELECT * FROM [dbo].IMEIUser", "SELECT * FROM dbo.LotteryLog", "SELECT * FROM [GreenPrize]", "SELECT * FROM [dbo].[Config]", "SELECT * FROM dbo.[Prize]", "SELECT * FROM [DBName].[dbo].[Config]", "SELECT * FROM table1, table2", "SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id", "SELECT sID, dtime FROM src JOIN dt ON src.sID=dt.dID" ] for i, sql in enumerate(test_sqls, 1): tables = extract_table_names(sql) print(f"SQL{i}: {sql}\n 表名 → {tables}\n") ``` #### 输出结果示例 ``` SQL1: SELECT * FROM Config 表名 → ['Config'] SQL2: SELECT * FROM [dbo].IMEIUser 表名 → ['IMEIUser'] SQL3: SELECT * FROM dbo.LotteryLog 表名 → ['LotteryLog'] SQL4: SELECT * FROM [GreenPrize] 表名 → ['GreenPrize'] SQL5: SELECT * FROM [dbo].[Config] 表名 → ['Config'] SQL9: SELECT * FROM table1 INNER JOIN table2 ON table1.id=table2.id 表名 → ['table1', 'table2'] SQL10: SELECT sID, dtime FROM src JOIN dt ON src.sID=dt.dID 表名 → ['src', 'dt'] ``` ### 正则表达式关键点解析 1. **多关键字匹配**: - 匹配 `FROM`、`JOIN` 和逗号分隔符 `,` - 使用 `(?:FROM\s+|JOIN\s+|,\s*)` 结构实现 2. **表名格式处理**: - 带方括号的表名:`\[[^\]]+\]`(如 `[dbo.Table]`) - 不带方括号的表名:`[^\s\.,;()]+`(排除特殊字符) - 前缀处理:`(?:\w+\s*\.\s*)*` 支持 `db.schema.table` 格式 3. **边界控制**: - 使用正向先行断言 `(?=\s|,|;|$)` 确保表名后是有效分隔符 - 避免匹配子查询(如 `FROM (SELECT ...)`) 4. **结果清洗**: - `re.sub(r'^\[|\]$', '', name)` 去除捕获的方括号 ### 应用场景与注意事项 1. **适用场景**: - SQL 日志分析 - 数据库血缘分析 - 查询优化审计 - 动态 SQL 生成 2. **已知限制**: - 不支持子查询中的表名提取(如 `FROM (SELECT ...) temp`) - 可能误提取字符串常量中的相似文本(如 `WHERE note = 'FROM table'`) - 复杂嵌套查询建议使用 SQL 解析器(如 `sqlparse` 或 `sqlglot`) > 对于生产环境的关键任务,建议结合 SQL 解析库如 [`sqlparse`](https://pypi.org/project/sqlparse/) 或 [`sqlglot`](https://github.com/tobymao/sqlglot) 获得更准确的结果[^2][^3]。
阅读全文

相关推荐

最新推荐

recommend-type

新能源车电机控制器:基于TI芯片的FOC算法源代码与实际应用

内容概要:本文详细介绍了基于TI芯片的FOC(场向量控制)算法在新能源车电机控制器中的应用。文章首先阐述了新能源车电机控制器的重要性及其对车辆性能的影响,接着深入探讨了FOC算法的工作原理,强调其在提高电机控制精度和能效方面的优势。随后,文章展示了完整的源代码资料,涵盖采样模块、CAN通信模块等多个关键部分,并指出这些代码不仅限于理论演示,而是来自实际量产的应用程序。此外,文中还特别提到代码遵循严格的规范,有助于读者理解和学习电机控制软件的最佳实践。 适合人群:从事新能源车研发的技术人员、电机控制工程师、嵌入式系统开发者以及对电机控制感兴趣的电子工程学生。 使用场景及目标:① 学习并掌握基于TI芯片的FOC算法的具体实现;② 理解电机控制器各模块的功能和交互方式;③ 提升实际项目开发能力,减少开发过程中遇到的问题。 其他说明:本文提供的源代码资料来源于早期已量产的新能源车控制器,因此具有较高的实用价值和参考意义。
recommend-type

中证500指数成分股历年调整名单2007至2023年 调入调出

中证500指数是中证指数有限公司开发的指数,样本空间内股票由全部A股中剔除沪深300指数成分股及总市值排名前300名的股票后,选取总市值排名靠前的500只股票组成,综合反映中国A股市场中一批中小市值公司的股票价格表现。包含字段:公告日期、变更日期、成份证券代码、成份证券简称、变动方式。各次调整日期:2006-12-26、2007-01-15、2007-06-01、2007-07-02、2007-12-10、2008-01-02、2008-06-04、2008-07-01、2008-12-15、2009-01-05、2009-05-05、2009-05-06、2009-06-15、2009-07-01、2009-08-10、2009-08-10。资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
recommend-type

基于28335的高精度旋变软解码技术及其应用 - 电机控制

内容概要:本文详细介绍了基于28335芯片实现的旋变软解码技术。该技术在0-360°范围内与TI方案相比,偏差极小(平均偏差最大为0.0009弧度),并且响应速度优于AD2S1205(解算器建立时间不超过5ms)。文中还讨论了信号解调方法,利用三角函数积化和差公式将旋变输出信号分解为高低频两部分,并通过锁相环和特殊设计的滤波器提高信号处理的精度和稳定性。最终,该技术在12位AD下能保证10-11位的精度。 适合人群:从事电机控制、自动化系统设计及相关领域的工程师和技术人员。 使用场景及目标:适用于需要高精度、快速响应的旋转变压器解码应用场景,如工业自动化、机器人技术和电动汽车等领域。目标是提供一种替代传统硬件解码方案的技术选择,提升系统的可靠性和性能。 阅读建议:读者可以通过本文深入了解旋变软解码的工作原理和技术细节,掌握其相对于现有解决方案的优势,从而更好地应用于实际项目中。
recommend-type

langchain4j-embeddings-bge-small-en-1.0.0-beta5.jar中文文档.zip

1、压缩文件中包含: 中文文档、jar包下载地址、Maven依赖、Gradle依赖、源代码下载地址。 2、使用方法: 解压最外层zip,再解压其中的zip包,双击 【index.html】 文件,即可用浏览器打开、进行查看。 3、特殊说明: (1)本文档为人性化翻译,精心制作,请放心使用; (2)只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; (3)不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 4、温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件。 5、本文件关键字: jar中文文档.zip,java,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,中文API文档,手册,开发手册,使用手册,参考手册。
recommend-type

苹果内购(IAP)人民币价格明细表

资源下载链接为: https://pan.quark.cn/s/9e7ef05254f8 在苹果的生态系统中,IAP(应用内购买)是苹果应用商店(App Store)中应用开发者常采用的一种盈利模式,允许用户在应用内直接购买虚拟商品或服务。苹果为开发者提供了一份详细的人民币(CNY)IAP定价表,这份定价表具有以下特点: 价格分级:定价表由多个价格等级组成,开发者可根据虚拟商品的价值选择相应等级,等级越高,价格越高。例如,低等级可能对应基础功能解锁,高等级则对应高级服务或大量虚拟道具。 税收与分成:苹果会从应用内购买金额中抽取30%作为服务费或佣金,这是苹果生态的固定规则。不过,开发者实际到手的收入会因不同国家和地区的税收政策而有所变化,但定价表中的价格等级本身是固定的,便于开发者统一管理。 多级定价策略:通过设置不同价格等级,开发者可以根据商品或服务的类型与价值进行合理定价,以满足不同消费能力的用户需求,从而最大化应用的总收入。例如,一款游戏可以通过设置不同等级的虚拟货币包,吸引不同付费意愿的玩家。 特殊等级:除了标准等级外,定价表还包含备用等级和特殊等级(如备用等级A、备用等级B等),这些等级可能是为应对特殊情况或促销活动而设置的额外价格点,为开发者提供了更灵活的定价选择。 苹果IAP定价表是开发者设计应用内购机制的重要参考。它不仅为开发者提供了标准的收入分成模型,还允许开发者根据产品特性设定价格等级,以适应市场和满足不同用户需求。同时,开发者在使用定价表时,还需严格遵守苹果的《App Store审查指南》,包括30%的分成政策、使用苹果支付接口、提供清晰的产品描述和定价信息等。苹果对应用内交易有严格规定,以确保交易的透明性和安全性。总之,苹果IAP定价表是开发者在应用内购设计中不可或缺的工具,但开发者也需密切关注苹果政策变化,以确保应用的合规运营和收益最大化。
recommend-type

掌握XFireSpring整合技术:HELLOworld原代码使用教程

标题:“xfirespring整合使用原代码”中提到的“xfirespring”是指将XFire和Spring框架进行整合使用。XFire是一个基于SOAP的Web服务框架,而Spring是一个轻量级的Java/Java EE全功能栈的应用程序框架。在Web服务开发中,将XFire与Spring整合能够发挥两者的优势,例如Spring的依赖注入、事务管理等特性,与XFire的简洁的Web服务开发模型相结合。 描述:“xfirespring整合使用HELLOworld原代码”说明了在这个整合过程中实现了一个非常基本的Web服务示例,即“HELLOworld”。这通常意味着创建了一个能够返回"HELLO world"字符串作为响应的Web服务方法。这个简单的例子用来展示如何设置环境、编写服务类、定义Web服务接口以及部署和测试整合后的应用程序。 标签:“xfirespring”表明文档、代码示例或者讨论集中于XFire和Spring的整合技术。 文件列表中的“index.jsp”通常是一个Web应用程序的入口点,它可能用于提供一个用户界面,通过这个界面调用Web服务或者展示Web服务的调用结果。“WEB-INF”是Java Web应用中的一个特殊目录,它存放了应用服务器加载的Servlet类文件和相关的配置文件,例如web.xml。web.xml文件中定义了Web应用程序的配置信息,如Servlet映射、初始化参数、安全约束等。“META-INF”目录包含了元数据信息,这些信息通常由部署工具使用,用于描述应用的元数据,如manifest文件,它记录了归档文件中的包信息以及相关的依赖关系。 整合XFire和Spring框架,具体知识点可以分为以下几个部分: 1. XFire框架概述 XFire是一个开源的Web服务框架,它是基于SOAP协议的,提供了一种简化的方式来创建、部署和调用Web服务。XFire支持多种数据绑定,包括XML、JSON和Java数据对象等。开发人员可以使用注解或者基于XML的配置来定义服务接口和服务实现。 2. Spring框架概述 Spring是一个全面的企业应用开发框架,它提供了丰富的功能,包括但不限于依赖注入、面向切面编程(AOP)、数据访问/集成、消息传递、事务管理等。Spring的核心特性是依赖注入,通过依赖注入能够将应用程序的组件解耦合,从而提高应用程序的灵活性和可测试性。 3. XFire和Spring整合的目的 整合这两个框架的目的是为了利用各自的优势。XFire可以用来创建Web服务,而Spring可以管理这些Web服务的生命周期,提供企业级服务,如事务管理、安全性、数据访问等。整合后,开发者可以享受Spring的依赖注入、事务管理等企业级功能,同时利用XFire的简洁的Web服务开发模型。 4. XFire与Spring整合的基本步骤 整合的基本步骤可能包括添加必要的依赖到项目中,配置Spring的applicationContext.xml,以包括XFire特定的bean配置。比如,需要配置XFire的ServiceExporter和ServicePublisher beans,使得Spring可以管理XFire的Web服务。同时,需要定义服务接口以及服务实现类,并通过注解或者XML配置将其关联起来。 5. Web服务实现示例:“HELLOworld” 实现一个Web服务通常涉及到定义服务接口和服务实现类。服务接口定义了服务的方法,而服务实现类则提供了这些方法的具体实现。在XFire和Spring整合的上下文中,“HELLOworld”示例可能包含一个接口定义,比如`HelloWorldService`,和一个实现类`HelloWorldServiceImpl`,该类有一个`sayHello`方法返回"HELLO world"字符串。 6. 部署和测试 部署Web服务时,需要将应用程序打包成WAR文件,并部署到支持Servlet 2.3及以上版本的Web应用服务器上。部署后,可以通过客户端或浏览器测试Web服务的功能,例如通过访问XFire提供的服务描述页面(WSDL)来了解如何调用服务。 7. JSP与Web服务交互 如果在应用程序中使用了JSP页面,那么JSP可以用来作为用户与Web服务交互的界面。例如,JSP可以包含JavaScript代码来发送异步的AJAX请求到Web服务,并展示返回的结果给用户。在这个过程中,JSP页面可能使用XMLHttpRequest对象或者现代的Fetch API与Web服务进行通信。 8. 项目配置文件说明 项目配置文件如web.xml和applicationContext.xml分别在Web应用和服务配置中扮演关键角色。web.xml负责定义Web组件,比如Servlet、过滤器和监听器,而applicationContext.xml则负责定义Spring容器中的bean,包括数据源、事务管理器、业务逻辑组件和服务访问器等。 总之,通过上述整合使用原代码的知识点,可以深入理解XFire与Spring框架的结合使用,以及如何开发和部署基本的Web服务。这些技术知识有助于进行更高层次的Web服务开发,以及在复杂的IT环境中灵活运用各种框架和工具。
recommend-type

【Unity2018汉化大揭秘】:一步到位优化中文用户体验

# 摘要 本论文详细介绍了Unity2018汉化项目的实施过程,从理论准备到实践步骤,再到后期的测试与优化,最终分享了汉化经验和心得。首先,强调了汉化项目对于用户体验提升和产品国际化的重要性,并分析了汉化资源的分类、识别与管理方法。接着,详细阐述了汉化工具的选择、脚本编写、资源手动调整等实践步骤,以及汉化质量测试、体验优化和项目维护更新的重要性。论文最后通过案例研究,分析了汉化中的挑战和应对策略,并预测了汉化技术未来的发展方向。整个汉化过程不仅涉及技术层面的操作,还包含了深入的理论研究和实践心得分享,对提升汉化项目的效率和质量具有指导意义。 # 关键字 Unity汉化;用户体验;国际化;资源
recommend-type

iPhone

<think>我们注意到用户意图不明确,但提到了“照片提取”和“其他功能帮助”。因此,我们需要通过搜索来获取关于iPhone照片提取的常见方法以及其他可能的功能帮助。由于用户问题比较宽泛,我们将重点放在照片提取上,因为这是明确提到的关键词。同时,我们也会考虑一些其他常用功能的帮助。首先,针对照片提取,可能涉及从iPhone导出照片、从备份中提取照片、或者从损坏的设备中恢复照片等。我们将搜索这些方面的信息。其次,关于其他功能帮助,我们可以提供一些常见问题的快速指南,如电池优化、屏幕时间管理等。根据要求,我们需要将答案组织为多个方法或步骤,并在每个步骤间换行。同时,避免使用第一人称和步骤词汇。由于
recommend-type

驾校一点通软件:提升驾驶证考试通过率

标题“驾校一点通”指向的是一款专门为学员考取驾驶证提供帮助的软件,该软件强调其辅助性质,旨在为学员提供便捷的学习方式和复习资料。从描述中可以推断出,“驾校一点通”是一个与驾驶考试相关的应用软件,这类软件一般包含驾驶理论学习、模拟考试、交通法规解释等内容。 文件标题中的“2007”这个年份标签很可能意味着软件的最初发布时间或版本更新年份,这说明了软件具有一定的历史背景和可能经过了多次更新,以适应不断变化的驾驶考试要求。 压缩包子文件的文件名称列表中,有以下几个文件类型值得关注: 1. images.dat:这个文件名表明,这是一个包含图像数据的文件,很可能包含了用于软件界面展示的图片,如各种标志、道路场景等图形。在驾照学习软件中,这类图片通常用于帮助用户认识和记忆不同交通标志、信号灯以及驾驶过程中需要注意的各种道路情况。 2. library.dat:这个文件名暗示它是一个包含了大量信息的库文件,可能包含了法规、驾驶知识、考试题库等数据。这类文件是提供给用户学习驾驶理论知识和准备科目一理论考试的重要资源。 3. 驾校一点通小型汽车专用.exe:这是一个可执行文件,是软件的主要安装程序。根据标题推测,这款软件主要是针对小型汽车驾照考试的学员设计的。通常,小型汽车(C1类驾照)需要学习包括车辆构造、基础驾驶技能、安全行车常识、交通法规等内容。 4. 使用说明.html:这个文件是软件使用说明的文档,通常以网页格式存在,用户可以通过浏览器阅读。使用说明应该会详细介绍软件的安装流程、功能介绍、如何使用软件的各种模块以及如何通过软件来帮助自己更好地准备考试。 综合以上信息,我们可以挖掘出以下几个相关知识点: - 软件类型:辅助学习软件,专门针对驾驶考试设计。 - 应用领域:主要用于帮助驾考学员准备理论和实践考试。 - 文件类型:包括图片文件(images.dat)、库文件(library.dat)、可执行文件(.exe)和网页格式的说明文件(.html)。 - 功能内容:可能包含交通法规知识学习、交通标志识别、驾驶理论学习、模拟考试、考试题库练习等功能。 - 版本信息:软件很可能最早发布于2007年,后续可能有多个版本更新。 - 用户群体:主要面向小型汽车驾照考生,即C1类驾照学员。 - 使用方式:用户需要将.exe安装文件进行安装,然后根据.html格式的使用说明来熟悉软件操作,从而利用images.dat和library.dat中的资源来辅助学习。 以上知识点为从给定文件信息中提炼出来的重点,这些内容对于了解“驾校一点通”这款软件的功能、作用、使用方法以及它的发展历史都有重要的指导意义。
recommend-type

【DFLauncher自动化教程】:简化游戏启动流程,让游戏体验更流畅

# 摘要 DFLauncher是一个功能丰富的游戏启动和管理平台,本论文将介绍其安装、基础使用、高级设置、社区互动以及插件开发等方面。通过对配置文件的解析、界面定制、自动化功能的实现、高级配置选项、安全性和性能监控的详细讨论,本文阐述了DFLauncher如何帮助用户更高效地管理和优化游戏环境。此外,本文还探讨了DFLauncher社区的资源分享、教育教程和插件开发等内容,