Robot Framework
String.py
Go to the documentation of this file.
1 # Copyright 2008-2015 Nokia Networks
2 # Copyright 2016- Robot Framework Foundation
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 import os
17 import re
18 from fnmatch import fnmatchcase
19 from random import randint
20 from string import ascii_lowercase, ascii_uppercase, digits
21 
22 from robot.api import logger
23 from robot.api.deco import keyword
24 from robot.utils import (FileReader, is_bytes, is_string, is_truthy,
25  parse_re_flags, safe_str, type_name)
26 from robot.version import get_version
27 
28 
29 
49 class String:
50  ROBOT_LIBRARY_SCOPE = 'GLOBAL'
51  ROBOT_LIBRARY_VERSION = get_version()
52 
53 
65  def convert_to_lower_case(self, string):
66  return string.lower()
67 
68 
80  def convert_to_upper_case(self, string):
81  return string.upper()
82 
83  @keyword(types=None)
84 
123  def convert_to_title_case(self, string, exclude=None):
124  if not is_string(string):
125  raise TypeError('This keyword works only with Unicode strings.')
126  if is_string(exclude):
127  exclude = [e.strip() for e in exclude.split(',')]
128  elif not exclude:
129  exclude = []
130  exclude = [re.compile('^%s$' % e) for e in exclude]
131 
132  def title(word):
133  if any(e.match(word) for e in exclude) or not word.islower():
134  return word
135  for index, char in enumerate(word):
136  if char.isalpha():
137  return word[:index] + word[index].title() + word[index+1:]
138  return word
139 
140  tokens = re.split(r'(\s+)', string, flags=re.UNICODE)
141  return ''.join(title(token) for token in tokens)
142 
143 
163  def encode_string_to_bytes(self, string, encoding, errors='strict'):
164  return bytes(string.encode(encoding, errors))
165 
166 
185  def decode_bytes_to_string(self, bytes, encoding, errors='strict'):
186  if is_string(bytes):
187  raise TypeError('Cannot decode strings.')
188  return bytes.decode(encoding, errors)
189 
190 
213  def format_string(self, template, *positional, **named):
214  if os.path.isabs(template) and os.path.isfile(template):
215  template = template.replace('/', os.sep)
216  logger.info('Reading template from file <a href="%s">%s</a>.'
217  % (template, template), html=True)
218  with FileReader(template) as reader:
219  template = reader.read()
220  return template.format(*positional, **named)
221 
222 
223  def get_line_count(self, string):
224  count = len(string.splitlines())
225  logger.info('%d lines' % count)
226  return count
227 
228 
248  def split_to_lines(self, string, start=0, end=None):
249  start = self._convert_to_index_convert_to_index(start, 'start')
250  end = self._convert_to_index_convert_to_index(end, 'end')
251  lines = string.splitlines()[start:end]
252  logger.info('%d lines returned' % len(lines))
253  return lines
254 
255 
267  def get_line(self, string, line_number):
268  line_number = self._convert_to_integer_convert_to_integer(line_number, 'line_number')
269  return string.splitlines()[line_number]
270 
271 
294  def get_lines_containing_string(self, string, pattern, case_insensitive=False):
295  if is_truthy(case_insensitive):
296  pattern = pattern.lower()
297  contains = lambda line: pattern in line.lower()
298  else:
299  contains = lambda line: pattern in line
300  return self._get_matching_lines_get_matching_lines(string, contains)
301 
302 
330  def get_lines_matching_pattern(self, string, pattern, case_insensitive=False):
331  if is_truthy(case_insensitive):
332  pattern = pattern.lower()
333  matches = lambda line: fnmatchcase(line.lower(), pattern)
334  else:
335  matches = lambda line: fnmatchcase(line, pattern)
336  return self._get_matching_lines_get_matching_lines(string, matches)
337 
338 
374  def get_lines_matching_regexp(self, string, pattern, partial_match=False, flags=None):
375  if is_truthy(partial_match):
376  match = re.compile(pattern, flags=parse_re_flags(flags)).search
377  else:
378  match = re.compile(pattern + '$', flags=parse_re_flags(flags)).match
379  return self._get_matching_lines_get_matching_lines(string, match)
380 
381  def _get_matching_lines(self, string, matches):
382  lines = string.splitlines()
383  matching = [line for line in lines if matches(line)]
384  logger.info('%d out of %d lines matched' % (len(matching), len(lines)))
385  return '\n'.join(matching)
386 
387 
421  def get_regexp_matches(self, string, pattern, *groups, flags=None):
422  regexp = re.compile(pattern, flags=parse_re_flags(flags))
423  groups = [self._parse_group_parse_group(g) for g in groups]
424  return [m.group(*groups) for m in regexp.finditer(string)]
425 
426  def _parse_group(self, group):
427  try:
428  return int(group)
429  except ValueError:
430  return group
431 
432 
452  def replace_string(self, string, search_for, replace_with, count=-1):
453  count = self._convert_to_integer_convert_to_integer(count, 'count')
454  return string.replace(search_for, replace_with, count)
455 
456 
477  def replace_string_using_regexp(self, string, pattern, replace_with, count=-1, flags=None):
478  count = self._convert_to_integer_convert_to_integer(count, 'count')
479  # re.sub handles 0 and negative counts differently than string.replace
480  if count == 0:
481  return string
482  return re.sub(pattern, replace_with, string, max(count, 0), flags=parse_re_flags(flags))
483 
484 
503  def remove_string(self, string, *removables):
504  for removable in removables:
505  string = self.replace_stringreplace_string(string, removable, '')
506  return string
507 
508 
524  def remove_string_using_regexp(self, string, *patterns, flags=None):
525  for pattern in patterns:
526  string = self.replace_string_using_regexpreplace_string_using_regexp(string, pattern, '', flags=flags)
527  return string
528 
529  @keyword(types=None)
530 
549  def split_string(self, string, separator=None, max_split=-1):
550  if separator == '':
551  separator = None
552  max_split = self._convert_to_integer_convert_to_integer(max_split, 'max_split')
553  return string.split(separator, max_split)
554 
555  @keyword(types=None)
556 
565  def split_string_from_right(self, string, separator=None, max_split=-1):
566  if separator == '':
567  separator = None
568  max_split = self._convert_to_integer_convert_to_integer(max_split, 'max_split')
569  return string.rsplit(separator, max_split)
570 
571 
576  def split_string_to_characters(self, string):
577  return list(string)
578 
579 
586  def fetch_from_left(self, string, marker):
587  return string.split(marker)[0]
588 
589 
596  def fetch_from_right(self, string, marker):
597  return string.split(marker)[-1]
598 
599 
625  def generate_random_string(self, length=8, chars='[LETTERS][NUMBERS]'):
626  if length == '':
627  length = 8
628  if isinstance(length, str) and re.match(r'^\d+-\d+$', length):
629  min_length, max_length = length.split('-')
630  length = randint(self._convert_to_integer_convert_to_integer(min_length, "length"),
631  self._convert_to_integer_convert_to_integer(max_length, "length"))
632  else:
633  length = self._convert_to_integer_convert_to_integer(length, 'length')
634  for name, value in [('[LOWER]', ascii_lowercase),
635  ('[UPPER]', ascii_uppercase),
636  ('[LETTERS]', ascii_lowercase + ascii_uppercase),
637  ('[NUMBERS]', digits)]:
638  chars = chars.replace(name, value)
639  maxi = len(chars) - 1
640  return ''.join(chars[randint(0, maxi)] for _ in range(length))
641 
642 
655  def get_substring(self, string, start, end=None):
656  start = self._convert_to_index_convert_to_index(start, 'start')
657  end = self._convert_to_index_convert_to_index(end, 'end')
658  return string[start:end]
659 
660  @keyword(types=None)
661 
681  def strip_string(self, string, mode='both', characters=None):
682  try:
683  method = {'BOTH': string.strip,
684  'LEFT': string.lstrip,
685  'RIGHT': string.rstrip,
686  'NONE': lambda characters: string}[mode.upper()]
687  except KeyError:
688  raise ValueError("Invalid mode '%s'." % mode)
689  return method(characters)
690 
691 
695  def should_be_string(self, item, msg=None):
696  if not is_string(item):
697  self._fail_fail(msg, "'%s' is %s, not a string.", item, type_name(item))
698 
699 
703  def should_not_be_string(self, item, msg=None):
704  if is_string(item):
705  self._fail_fail(msg, "'%s' is a string.", item)
706 
707 
712  def should_be_unicode_string(self, item, msg=None):
713  if not is_string(item):
714  self._fail_fail(msg, "'%s' is not a Unicode string.", item)
715 
716 
722  def should_be_byte_string(self, item, msg=None):
723  if not is_bytes(item):
724  self._fail_fail(msg, "'%s' is not a byte string.", item)
725 
726 
736  def should_be_lower_case(self, string, msg=None):
737  if not string.islower():
738  self._fail_fail(msg, "'%s' is not lower case.", string)
739 
740 
750  def should_be_upper_case(self, string, msg=None):
751  if not string.isupper():
752  self._fail_fail(msg, "'%s' is not upper case.", string)
753 
754  @keyword(types=None)
755 
783  def should_be_title_case(self, string, msg=None, exclude=None):
784  if string != self.convert_to_title_caseconvert_to_title_case(string, exclude):
785  self._fail_fail(msg, "'%s' is not title case.", string)
786 
787  def _convert_to_index(self, value, name):
788  if value == '':
789  return 0
790  if value is None:
791  return None
792  return self._convert_to_integer_convert_to_integer(value, name)
793 
794  def _convert_to_integer(self, value, name):
795  try:
796  return int(value)
797  except ValueError:
798  raise ValueError("Cannot convert '%s' argument '%s' to an integer."
799  % (name, value))
800 
801  def _fail(self, message, default_template, *items):
802  if not message:
803  message = default_template % tuple(safe_str(item) for item in items)
804  raise AssertionError(message)
A library for string manipulation and verification.
Definition: String.py:49
def format_string(self, template, *positional, **named)
Formats a template using the given positional and named arguments.
Definition: String.py:213
def should_be_byte_string(self, item, msg=None)
Fails if the given item is not a byte string.
Definition: String.py:722
def should_be_lower_case(self, string, msg=None)
Fails if the given string is not in lower case.
Definition: String.py:736
def fetch_from_left(self, string, marker)
Returns contents of the string before the first occurrence of marker.
Definition: String.py:586
def strip_string(self, string, mode='both', characters=None)
Remove leading and/or trailing whitespaces from the given string.
Definition: String.py:681
def remove_string(self, string, *removables)
Removes all removables from the given string.
Definition: String.py:503
def encode_string_to_bytes(self, string, encoding, errors='strict')
Encodes the given Unicode string to bytes using the given encoding.
Definition: String.py:163
def should_be_title_case(self, string, msg=None, exclude=None)
Fails if given string is not title.
Definition: String.py:783
def split_string(self, string, separator=None, max_split=-1)
Splits the string using separator as a delimiter string.
Definition: String.py:549
def get_regexp_matches(self, string, pattern, *groups, flags=None)
Returns a list of all non-overlapping matches in the given string.
Definition: String.py:421
def should_be_unicode_string(self, item, msg=None)
Fails if the given item is not a Unicode string.
Definition: String.py:712
def _parse_group(self, group)
Definition: String.py:426
def get_line_count(self, string)
Returns and logs the number of lines in the given string.
Definition: String.py:223
def _fail(self, message, default_template, *items)
Definition: String.py:801
def get_line(self, string, line_number)
Returns the specified line from the given string.
Definition: String.py:267
def get_lines_matching_pattern(self, string, pattern, case_insensitive=False)
Returns lines of the given string that match the pattern.
Definition: String.py:330
def _convert_to_integer(self, value, name)
Definition: String.py:794
def should_be_string(self, item, msg=None)
Fails if the given item is not a string.
Definition: String.py:695
def _convert_to_index(self, value, name)
Definition: String.py:787
def replace_string(self, string, search_for, replace_with, count=-1)
Replaces search_for in the given string with replace_with.
Definition: String.py:452
def split_string_to_characters(self, string)
Splits the given string to characters.
Definition: String.py:576
def _get_matching_lines(self, string, matches)
Definition: String.py:381
def replace_string_using_regexp(self, string, pattern, replace_with, count=-1, flags=None)
Replaces pattern in the given string with replace_with.
Definition: String.py:477
def convert_to_lower_case(self, string)
Converts string to lower case.
Definition: String.py:65
def get_lines_containing_string(self, string, pattern, case_insensitive=False)
Returns lines of the given string that contain the pattern.
Definition: String.py:294
def should_be_upper_case(self, string, msg=None)
Fails if the given string is not in upper case.
Definition: String.py:750
def fetch_from_right(self, string, marker)
Returns contents of the string after the last occurrence of marker.
Definition: String.py:596
def split_string_from_right(self, string, separator=None, max_split=-1)
Splits the string using separator starting from right.
Definition: String.py:565
def generate_random_string(self, length=8, chars='[LETTERS][NUMBERS]')
Generates a string with a desired length from the given chars.
Definition: String.py:625
def get_lines_matching_regexp(self, string, pattern, partial_match=False, flags=None)
Returns lines of the given string that match the regexp pattern.
Definition: String.py:374
def convert_to_upper_case(self, string)
Converts string to upper case.
Definition: String.py:80
def get_substring(self, string, start, end=None)
Returns a substring from start index to end index.
Definition: String.py:655
def remove_string_using_regexp(self, string, *patterns, flags=None)
Removes patterns from the given string.
Definition: String.py:524
def decode_bytes_to_string(self, bytes, encoding, errors='strict')
Decodes the given bytes to a Unicode string using the given encoding.
Definition: String.py:185
def convert_to_title_case(self, string, exclude=None)
Converts string to title case.
Definition: String.py:123
def should_not_be_string(self, item, msg=None)
Fails if the given item is a string.
Definition: String.py:703
def split_to_lines(self, string, start=0, end=None)
Splits the given string to lines.
Definition: String.py:248
def parse_re_flags(flags=None)
Definition: misc.py:128
def is_truthy(item)
Returns True or False depending on is the item considered true or not.
Definition: robottypes.py:162
def type_name(item, capitalize=False)
Return "non-technical" type name for objects and types.
Definition: robottypes.py:86
def safe_str(item)
Definition: unic.py:21
def get_version(naked=False)
Definition: version.py:24